ictrp-mcp-server 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +65 -0
- package/LICENSE +37 -0
- package/README.md +208 -0
- package/README_ZH.md +189 -0
- package/dist/cli/setup-cli.d.ts +14 -0
- package/dist/cli/setup-cli.js +230 -0
- package/dist/cli/setup-cli.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +477 -0
- package/dist/index.js.map +1 -0
- package/dist/runtime/bootstrap.d.ts +99 -0
- package/dist/runtime/bootstrap.js +350 -0
- package/dist/runtime/bootstrap.js.map +1 -0
- package/dist/runtime/env-probe.d.ts +108 -0
- package/dist/runtime/env-probe.js +479 -0
- package/dist/runtime/env-probe.js.map +1 -0
- package/dist/runtime/sidecar-client.d.ts +50 -0
- package/dist/runtime/sidecar-client.js +120 -0
- package/dist/runtime/sidecar-client.js.map +1 -0
- package/dist/runtime/supervisor.d.ts +47 -0
- package/dist/runtime/supervisor.js +248 -0
- package/dist/runtime/supervisor.js.map +1 -0
- package/package.json +60 -0
- package/sidecar/ictrp_sidecar.py +602 -0
- package/sidecar/vendor/ictrp_mcp/__init__.py +3 -0
- package/sidecar/vendor/ictrp_mcp/cache/__init__.py +0 -0
- package/sidecar/vendor/ictrp_mcp/cache/store.py +313 -0
- package/sidecar/vendor/ictrp_mcp/data/__init__.py +0 -0
- package/sidecar/vendor/ictrp_mcp/data/columns.py +108 -0
- package/sidecar/vendor/ictrp_mcp/data/jsonio.py +213 -0
- package/sidecar/vendor/ictrp_mcp/data/normalize.py +348 -0
- package/sidecar/vendor/ictrp_mcp/data/query.py +307 -0
- package/sidecar/vendor/ictrp_mcp/errors.py +123 -0
- package/sidecar/vendor/ictrp_mcp/ictrp/__init__.py +0 -0
- package/sidecar/vendor/ictrp_mcp/ictrp/export_guard.py +269 -0
- package/sidecar/vendor/ictrp_mcp/ictrp/htmlstate.py +143 -0
- package/sidecar/vendor/ictrp_mcp/ictrp/session.py +245 -0
- package/sidecar/vendor/ictrp_mcp/offline.py +133 -0
- package/sidecar/vendor/ictrp_mcp/provenance.py +182 -0
- package/sidecar/vendor/ictrp_mcp/server.py +368 -0
- package/sidecar/vendor/ictrp_mcp/tools.py +712 -0
- package/sidecar/vendor/pyproject.toml +25 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sidecar-client.js","sourceRoot":"","sources":["../../src/runtime/sidecar-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sidecar supervisor: start the Python process, wait for it to answer, stop it.
|
|
3
|
+
*
|
|
4
|
+
* The supervisor's whole job is to make "the sidecar is not running" a
|
|
5
|
+
* transient condition rather than an error the user has to understand. It
|
|
6
|
+
* starts lazily -- the first tool call that needs it triggers the spawn -- and
|
|
7
|
+
* it never starts more than one.
|
|
8
|
+
*
|
|
9
|
+
* Two details that are easy to get wrong and expensive to debug:
|
|
10
|
+
*
|
|
11
|
+
* - The child's stdout must not be inherited. stdout is the MCP protocol
|
|
12
|
+
* channel; a stray byte from Python corrupts the stream and the client
|
|
13
|
+
* sees a protocol error rather than a print statement. The sidecar's output
|
|
14
|
+
* is captured and forwarded to stderr.
|
|
15
|
+
*
|
|
16
|
+
* - Readiness is a successful `/health` response, not "the process exists".
|
|
17
|
+
* A Python process that started and immediately died on an ImportError
|
|
18
|
+
* exists for long enough to fool a naive check.
|
|
19
|
+
*/
|
|
20
|
+
import { type SidecarResult, type HealthPayload } from "./sidecar-client.js";
|
|
21
|
+
export declare function sidecarLogTail(): string[];
|
|
22
|
+
export declare function isSidecarSpawned(): boolean;
|
|
23
|
+
export declare function sidecarPid(): number | undefined;
|
|
24
|
+
/**
|
|
25
|
+
* Spawn the sidecar and wait until it answers.
|
|
26
|
+
*
|
|
27
|
+
* Concurrent callers share one startup attempt: two tool calls racing on a cold
|
|
28
|
+
* start must not produce two Python processes fighting over the same port.
|
|
29
|
+
*/
|
|
30
|
+
export declare function ensureSidecar(opts?: {
|
|
31
|
+
autoStart?: boolean;
|
|
32
|
+
}): Promise<SidecarResult<HealthPayload>>;
|
|
33
|
+
/**
|
|
34
|
+
* Stop the sidecar.
|
|
35
|
+
*
|
|
36
|
+
* SIGTERM first so the sidecar can close its HTTP server and flush, then
|
|
37
|
+
* SIGKILL if it does not go. Called on process exit and on `ictrp-setup clean`.
|
|
38
|
+
*/
|
|
39
|
+
export declare function stopSidecar(timeoutMs?: number): Promise<void>;
|
|
40
|
+
/**
|
|
41
|
+
* Arrange for the sidecar to be stopped when this process ends.
|
|
42
|
+
*
|
|
43
|
+
* Registered once at startup. Without it, an MCP client that closes the stdio
|
|
44
|
+
* stream leaves an orphaned Python process holding the port, and the next
|
|
45
|
+
* launch fails to bind.
|
|
46
|
+
*/
|
|
47
|
+
export declare function installShutdownHooks(): void;
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sidecar supervisor: start the Python process, wait for it to answer, stop it.
|
|
3
|
+
*
|
|
4
|
+
* The supervisor's whole job is to make "the sidecar is not running" a
|
|
5
|
+
* transient condition rather than an error the user has to understand. It
|
|
6
|
+
* starts lazily -- the first tool call that needs it triggers the spawn -- and
|
|
7
|
+
* it never starts more than one.
|
|
8
|
+
*
|
|
9
|
+
* Two details that are easy to get wrong and expensive to debug:
|
|
10
|
+
*
|
|
11
|
+
* - The child's stdout must not be inherited. stdout is the MCP protocol
|
|
12
|
+
* channel; a stray byte from Python corrupts the stream and the client
|
|
13
|
+
* sees a protocol error rather than a print statement. The sidecar's output
|
|
14
|
+
* is captured and forwarded to stderr.
|
|
15
|
+
*
|
|
16
|
+
* - Readiness is a successful `/health` response, not "the process exists".
|
|
17
|
+
* A Python process that started and immediately died on an ImportError
|
|
18
|
+
* exists for long enough to fool a naive check.
|
|
19
|
+
*/
|
|
20
|
+
import { spawn } from "node:child_process";
|
|
21
|
+
import { existsSync } from "node:fs";
|
|
22
|
+
import { pingSidecar } from "./sidecar-client.js";
|
|
23
|
+
import { sidecarBaseUrl, sidecarScript, venvPython } from "./env-probe.js";
|
|
24
|
+
/** How long to wait for a freshly spawned sidecar to answer /health. */
|
|
25
|
+
const READY_TIMEOUT_MS = 20_000;
|
|
26
|
+
const READY_POLL_MS = 250;
|
|
27
|
+
let child;
|
|
28
|
+
let starting;
|
|
29
|
+
/** Recent sidecar stderr, kept so a failed start can explain itself. */
|
|
30
|
+
const recentOutput = [];
|
|
31
|
+
const MAX_RECENT_LINES = 40;
|
|
32
|
+
function log(message) {
|
|
33
|
+
// stderr only. stdout belongs to the MCP transport.
|
|
34
|
+
process.stderr.write(`[ictrp-sidecar] ${message}\n`);
|
|
35
|
+
}
|
|
36
|
+
function remember(line) {
|
|
37
|
+
recentOutput.push(line);
|
|
38
|
+
if (recentOutput.length > MAX_RECENT_LINES)
|
|
39
|
+
recentOutput.shift();
|
|
40
|
+
}
|
|
41
|
+
export function sidecarLogTail() {
|
|
42
|
+
return [...recentOutput];
|
|
43
|
+
}
|
|
44
|
+
export function isSidecarSpawned() {
|
|
45
|
+
return !!child && !child.killed && child.exitCode === null;
|
|
46
|
+
}
|
|
47
|
+
export function sidecarPid() {
|
|
48
|
+
return child?.pid;
|
|
49
|
+
}
|
|
50
|
+
function parsePort() {
|
|
51
|
+
const raw = process.env.ICTRP_SIDECAR_PORT;
|
|
52
|
+
const parsed = raw ? Number(raw) : NaN;
|
|
53
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : 8849;
|
|
54
|
+
}
|
|
55
|
+
function host() {
|
|
56
|
+
return process.env.ICTRP_SIDECAR_HOST?.trim() || "127.0.0.1";
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Spawn the sidecar and wait until it answers.
|
|
60
|
+
*
|
|
61
|
+
* Concurrent callers share one startup attempt: two tool calls racing on a cold
|
|
62
|
+
* start must not produce two Python processes fighting over the same port.
|
|
63
|
+
*/
|
|
64
|
+
export async function ensureSidecar(opts = {}) {
|
|
65
|
+
const autoStart = opts.autoStart ?? process.env.ICTRP_AUTOSTART_SIDECAR !== "0";
|
|
66
|
+
const alive = await pingSidecar();
|
|
67
|
+
if (alive.ok)
|
|
68
|
+
return alive;
|
|
69
|
+
if (!autoStart) {
|
|
70
|
+
return {
|
|
71
|
+
ok: false,
|
|
72
|
+
code: "SIDECAR_NOT_RUNNING",
|
|
73
|
+
message: `sidecar is not running at ${sidecarBaseUrl()} and autostart is disabled`,
|
|
74
|
+
retryable: true,
|
|
75
|
+
hint: "Start it with `npx ictrp-setup sidecar`.",
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
if (starting)
|
|
79
|
+
return starting;
|
|
80
|
+
const promise = startAndWait();
|
|
81
|
+
starting = promise;
|
|
82
|
+
try {
|
|
83
|
+
return await promise;
|
|
84
|
+
}
|
|
85
|
+
finally {
|
|
86
|
+
if (starting === promise)
|
|
87
|
+
starting = undefined;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
async function startAndWait() {
|
|
91
|
+
const python = venvPython();
|
|
92
|
+
const script = sidecarScript();
|
|
93
|
+
if (!existsSync(python)) {
|
|
94
|
+
return {
|
|
95
|
+
ok: false,
|
|
96
|
+
code: "SIDECAR_NO_VENV",
|
|
97
|
+
message: `no interpreter at ${python}`,
|
|
98
|
+
retryable: false,
|
|
99
|
+
hint: "Run `npx ictrp-setup setup` to create the private Python environment.",
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
if (!existsSync(script)) {
|
|
103
|
+
return {
|
|
104
|
+
ok: false,
|
|
105
|
+
code: "SIDECAR_NO_SCRIPT",
|
|
106
|
+
message: `no sidecar script at ${script}`,
|
|
107
|
+
retryable: false,
|
|
108
|
+
hint: "The package is incomplete; reinstall it.",
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
const port = parsePort();
|
|
112
|
+
const args = [script, "--host", host(), "--port", String(port)];
|
|
113
|
+
log(`starting: ${python} ${args.join(" ")}`);
|
|
114
|
+
recentOutput.length = 0;
|
|
115
|
+
child = spawn(python, args, {
|
|
116
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
117
|
+
windowsHide: true,
|
|
118
|
+
env: {
|
|
119
|
+
...process.env,
|
|
120
|
+
PYTHONUNBUFFERED: "1",
|
|
121
|
+
ICTRP_SIDECAR_HOST: host(),
|
|
122
|
+
ICTRP_SIDECAR_PORT: String(port),
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
child.stdout?.on("data", (buf) => {
|
|
126
|
+
for (const line of buf.toString("utf8").split(/[\r\n]+/)) {
|
|
127
|
+
if (line.trim())
|
|
128
|
+
remember(line.trim());
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
child.stderr?.on("data", (buf) => {
|
|
132
|
+
for (const line of buf.toString("utf8").split(/[\r\n]+/)) {
|
|
133
|
+
const trimmed = line.trim();
|
|
134
|
+
if (!trimmed)
|
|
135
|
+
continue;
|
|
136
|
+
remember(trimmed);
|
|
137
|
+
log(trimmed);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
let spawnError;
|
|
141
|
+
child.on("error", (err) => {
|
|
142
|
+
spawnError = err.message;
|
|
143
|
+
log(`spawn error: ${err.message}`);
|
|
144
|
+
});
|
|
145
|
+
let exited;
|
|
146
|
+
child.on("exit", (code, signal) => {
|
|
147
|
+
exited = { code, signal };
|
|
148
|
+
log(`exited (code=${code ?? "null"} signal=${signal ?? "null"})`);
|
|
149
|
+
child = undefined;
|
|
150
|
+
});
|
|
151
|
+
const deadline = Date.now() + READY_TIMEOUT_MS;
|
|
152
|
+
while (Date.now() < deadline) {
|
|
153
|
+
await sleep(READY_POLL_MS);
|
|
154
|
+
if (spawnError) {
|
|
155
|
+
return {
|
|
156
|
+
ok: false,
|
|
157
|
+
code: "SIDECAR_SPAWN_FAILED",
|
|
158
|
+
message: `could not spawn the sidecar: ${spawnError}`,
|
|
159
|
+
retryable: false,
|
|
160
|
+
hint: "Check that the venv interpreter is executable.",
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
if (exited) {
|
|
164
|
+
// The process died. Its last words are the most useful thing we have.
|
|
165
|
+
const tail = sidecarLogTail().slice(-8).join("\n");
|
|
166
|
+
return {
|
|
167
|
+
ok: false,
|
|
168
|
+
code: "SIDECAR_DIED",
|
|
169
|
+
message: `sidecar exited immediately (code=${exited.code ?? "null"})${tail ? `:\n${tail}` : ""}`,
|
|
170
|
+
retryable: false,
|
|
171
|
+
hint: "Run `npx ictrp-setup doctor` for a full environment report.",
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
const health = await pingSidecar();
|
|
175
|
+
if (health.ok) {
|
|
176
|
+
log(`ready (pid ${child?.pid ?? "?"})`);
|
|
177
|
+
return health;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return {
|
|
181
|
+
ok: false,
|
|
182
|
+
code: "SIDECAR_START_TIMEOUT",
|
|
183
|
+
message: `sidecar did not answer /health within ${READY_TIMEOUT_MS}ms`,
|
|
184
|
+
retryable: true,
|
|
185
|
+
hint: `Check that port ${port} is free, or set ICTRP_SIDECAR_PORT.`,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
function sleep(ms) {
|
|
189
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Stop the sidecar.
|
|
193
|
+
*
|
|
194
|
+
* SIGTERM first so the sidecar can close its HTTP server and flush, then
|
|
195
|
+
* SIGKILL if it does not go. Called on process exit and on `ictrp-setup clean`.
|
|
196
|
+
*/
|
|
197
|
+
export async function stopSidecar(timeoutMs = 5_000) {
|
|
198
|
+
const proc = child;
|
|
199
|
+
if (!proc || proc.exitCode !== null) {
|
|
200
|
+
child = undefined;
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
await new Promise((resolve) => {
|
|
204
|
+
const done = () => {
|
|
205
|
+
clearTimeout(killTimer);
|
|
206
|
+
resolve();
|
|
207
|
+
};
|
|
208
|
+
const killTimer = setTimeout(() => {
|
|
209
|
+
log("did not exit on SIGTERM; killing");
|
|
210
|
+
try {
|
|
211
|
+
proc.kill("SIGKILL");
|
|
212
|
+
}
|
|
213
|
+
catch {
|
|
214
|
+
/* already gone */
|
|
215
|
+
}
|
|
216
|
+
resolve();
|
|
217
|
+
}, timeoutMs);
|
|
218
|
+
proc.once("exit", done);
|
|
219
|
+
try {
|
|
220
|
+
proc.kill("SIGTERM");
|
|
221
|
+
}
|
|
222
|
+
catch {
|
|
223
|
+
clearTimeout(killTimer);
|
|
224
|
+
resolve();
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
child = undefined;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Arrange for the sidecar to be stopped when this process ends.
|
|
231
|
+
*
|
|
232
|
+
* Registered once at startup. Without it, an MCP client that closes the stdio
|
|
233
|
+
* stream leaves an orphaned Python process holding the port, and the next
|
|
234
|
+
* launch fails to bind.
|
|
235
|
+
*/
|
|
236
|
+
export function installShutdownHooks() {
|
|
237
|
+
const shutdown = () => {
|
|
238
|
+
void stopSidecar(2_000);
|
|
239
|
+
};
|
|
240
|
+
process.once("exit", shutdown);
|
|
241
|
+
process.once("SIGINT", () => {
|
|
242
|
+
void stopSidecar(2_000).then(() => process.exit(130));
|
|
243
|
+
});
|
|
244
|
+
process.once("SIGTERM", () => {
|
|
245
|
+
void stopSidecar(2_000).then(() => process.exit(143));
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
//# sourceMappingURL=supervisor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"supervisor.js","sourceRoot":"","sources":["../../src/runtime/supervisor.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ictrp-mcp-server",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server for the WHO International Clinical Trials Registry Platform (ICTRP). Plain HTTP, no browser. Every response is explicit about the export's known incompleteness.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"ictrp-mcp-server": "./dist/index.js",
|
|
10
|
+
"ictrp-setup": "./dist/cli/setup-cli.js"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"dist",
|
|
14
|
+
"sidecar",
|
|
15
|
+
"README.md",
|
|
16
|
+
"README_ZH.md",
|
|
17
|
+
"CHANGELOG.md",
|
|
18
|
+
"LICENSE"
|
|
19
|
+
],
|
|
20
|
+
"engines": {
|
|
21
|
+
"node": ">=20"
|
|
22
|
+
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsc",
|
|
25
|
+
"prepare": "npm run build",
|
|
26
|
+
"prepack": "node scripts/prune-tests.mjs",
|
|
27
|
+
"cli": "node dist/index.js",
|
|
28
|
+
"doctor": "node dist/cli/setup-cli.js doctor",
|
|
29
|
+
"setup": "node dist/cli/setup-cli.js setup",
|
|
30
|
+
"sidecar": "node dist/cli/setup-cli.js sidecar",
|
|
31
|
+
"postinstall": "node dist/cli/setup-cli.js postinstall",
|
|
32
|
+
"vendor": "node scripts/vendor-sidecar.mjs",
|
|
33
|
+
"prepublishOnly": "npm run build && npm run vendor && node scripts/prune-tests.mjs"
|
|
34
|
+
},
|
|
35
|
+
"keywords": [
|
|
36
|
+
"mcp",
|
|
37
|
+
"model-context-protocol",
|
|
38
|
+
"clinical-trials",
|
|
39
|
+
"ictrp",
|
|
40
|
+
"who",
|
|
41
|
+
"trial-registry",
|
|
42
|
+
"chictr"
|
|
43
|
+
],
|
|
44
|
+
"license": "MIT",
|
|
45
|
+
"repository": {
|
|
46
|
+
"type": "git",
|
|
47
|
+
"url": "git+ssh://git@github.com/opencare-skillhub/ictrp-mcp-service.git"
|
|
48
|
+
},
|
|
49
|
+
"homepage": "https://github.com/opencare-skillhub/ictrp-mcp-service#readme",
|
|
50
|
+
"bugs": {
|
|
51
|
+
"url": "https://github.com/opencare-skillhub/ictrp-mcp-service/issues"
|
|
52
|
+
},
|
|
53
|
+
"dependencies": {
|
|
54
|
+
"@modelcontextprotocol/sdk": "^1.22.0"
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@types/node": "^22.10.0",
|
|
58
|
+
"typescript": "^5.9.3"
|
|
59
|
+
}
|
|
60
|
+
}
|