justlabs-mcp-server 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,94 @@
1
+ # JustLabs MCP Server
2
+
3
+ An MCP (Model Context Protocol) server that lets Claude search for lab tests, get pricing, and make recommendations from JustLabs.
4
+
5
+ ## What is MCP?
6
+
7
+ MCP is Anthropic's open protocol that allows AI assistants like Claude to connect to external tools and data sources. This server exposes JustLabs' lab test catalog to Claude users.
8
+
9
+ ## Available Tools
10
+
11
+ | Tool | Description |
12
+ |------|-------------|
13
+ | `search_lab_tests` | Search tests by name, category, or symptoms |
14
+ | `get_test_details` | Get detailed info about a specific test |
15
+ | `get_test_panels` | Browse bundled test panels |
16
+ | `recommend_tests` | Get recommendations based on symptoms |
17
+ | `get_pricing` | Get pricing for specific tests |
18
+
19
+ ## Installation
20
+
21
+ ### 1. Build the server
22
+
23
+ ```bash
24
+ cd mcp-server
25
+ npm install
26
+ npm run build
27
+ ```
28
+
29
+ ### 2. Configure Claude Desktop
30
+
31
+ Add to your Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json` on Mac):
32
+
33
+ ```json
34
+ {
35
+ "mcpServers": {
36
+ "justlabs": {
37
+ "command": "node",
38
+ "args": ["/path/to/labify/mcp-server/dist/index.js"]
39
+ }
40
+ }
41
+ }
42
+ ```
43
+
44
+ ### 3. Restart Claude Desktop
45
+
46
+ The JustLabs tools will now be available in Claude.
47
+
48
+ ## Example Queries
49
+
50
+ Once configured, you can ask Claude things like:
51
+
52
+ - "What lab tests should I get for fatigue?"
53
+ - "How much does a thyroid panel cost at JustLabs?"
54
+ - "Search for tests related to cholesterol"
55
+ - "I have brain fog and weight gain, what tests do you recommend?"
56
+ - "What's included in the comprehensive metabolic panel?"
57
+
58
+ ## Publishing to npm (Optional)
59
+
60
+ To make it easier for users to install:
61
+
62
+ ```bash
63
+ npm publish
64
+ ```
65
+
66
+ Then users can install globally:
67
+
68
+ ```bash
69
+ npm install -g justlabs-mcp-server
70
+ ```
71
+
72
+ And configure Claude with:
73
+
74
+ ```json
75
+ {
76
+ "mcpServers": {
77
+ "justlabs": {
78
+ "command": "justlabs-mcp"
79
+ }
80
+ }
81
+ }
82
+ ```
83
+
84
+ ## Development
85
+
86
+ ```bash
87
+ npm run dev # Watch mode
88
+ npm run build # Build for production
89
+ npm start # Run the server
90
+ ```
91
+
92
+ ## License
93
+
94
+ MIT
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,446 @@
1
+ #!/usr/bin/env node
2
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
5
+ // Lab test data (subset of popular tests)
6
+ const labTests = [
7
+ {
8
+ id: "tsh",
9
+ name: "TSH (Thyroid Stimulating Hormone)",
10
+ shortName: "TSH",
11
+ description: "Measures thyroid-stimulating hormone to evaluate thyroid function. The most sensitive marker for detecting thyroid disorders.",
12
+ category: "thyroid",
13
+ price: 8,
14
+ fastingRequired: false,
15
+ turnaroundDays: "1-2",
16
+ popular: true,
17
+ biomarkers: ["TSH"],
18
+ symptomsAddressed: ["Fatigue", "Weight gain", "Weight loss", "Cold intolerance", "Hair loss", "Brain fog"],
19
+ url: "https://justlabs.health/tests/tsh",
20
+ },
21
+ {
22
+ id: "free-t4",
23
+ name: "Free T4 (Thyroxine)",
24
+ shortName: "Free T4",
25
+ description: "Measures the unbound, active form of thyroid hormone T4. Helps assess thyroid function.",
26
+ category: "thyroid",
27
+ price: 8,
28
+ fastingRequired: false,
29
+ turnaroundDays: "1-2",
30
+ biomarkers: ["Free T4"],
31
+ symptomsAddressed: ["Fatigue", "Weight changes", "Hair loss", "Mood changes"],
32
+ url: "https://justlabs.health/tests/free-t4",
33
+ },
34
+ {
35
+ id: "free-t3",
36
+ name: "Free T3 (Triiodothyronine)",
37
+ shortName: "Free T3",
38
+ description: "Measures the active thyroid hormone T3. Important for evaluating thyroid function.",
39
+ category: "thyroid",
40
+ price: 15,
41
+ fastingRequired: false,
42
+ turnaroundDays: "1-2",
43
+ biomarkers: ["Free T3"],
44
+ symptomsAddressed: ["Fatigue", "Weight issues", "Metabolism problems"],
45
+ url: "https://justlabs.health/tests/free-t3",
46
+ },
47
+ {
48
+ id: "lipid-panel",
49
+ name: "Lipid Panel",
50
+ shortName: "Lipid Panel",
51
+ description: "Complete cholesterol test including Total Cholesterol, LDL, HDL, and Triglycerides. Essential for cardiovascular health.",
52
+ category: "cardiovascular",
53
+ price: 10,
54
+ fastingRequired: true,
55
+ turnaroundDays: "1-2",
56
+ popular: true,
57
+ biomarkers: ["Total Cholesterol", "LDL", "HDL", "Triglycerides", "VLDL"],
58
+ symptomsAddressed: ["Heart disease risk", "High cholesterol family history"],
59
+ url: "https://justlabs.health/tests/lipid-panel",
60
+ },
61
+ {
62
+ id: "cmp",
63
+ name: "Comprehensive Metabolic Panel (CMP)",
64
+ shortName: "CMP",
65
+ description: "14-test panel measuring glucose, kidney function, liver function, and electrolytes.",
66
+ category: "metabolic",
67
+ price: 10,
68
+ fastingRequired: true,
69
+ turnaroundDays: "1-2",
70
+ popular: true,
71
+ biomarkers: ["Glucose", "BUN", "Creatinine", "Sodium", "Potassium", "Chloride", "CO2", "Calcium", "Total Protein", "Albumin", "Bilirubin", "Alkaline Phosphatase", "AST", "ALT"],
72
+ symptomsAddressed: ["General health screening", "Fatigue", "Diabetes risk"],
73
+ url: "https://justlabs.health/tests/cmp",
74
+ },
75
+ {
76
+ id: "hba1c",
77
+ name: "Hemoglobin A1c",
78
+ shortName: "HbA1c",
79
+ description: "Measures average blood sugar over 2-3 months. Gold standard for diabetes screening and monitoring.",
80
+ category: "diabetes",
81
+ price: 12,
82
+ fastingRequired: false,
83
+ turnaroundDays: "1-2",
84
+ popular: true,
85
+ biomarkers: ["HbA1c"],
86
+ symptomsAddressed: ["Diabetes risk", "Blood sugar concerns", "Prediabetes monitoring"],
87
+ url: "https://justlabs.health/tests/hba1c",
88
+ },
89
+ {
90
+ id: "vitamin-d",
91
+ name: "Vitamin D, 25-Hydroxy",
92
+ shortName: "Vitamin D",
93
+ description: "Measures vitamin D levels. Deficiency is extremely common and linked to fatigue, bone health, and immune function.",
94
+ category: "vitamins",
95
+ price: 15,
96
+ fastingRequired: false,
97
+ turnaroundDays: "1-2",
98
+ popular: true,
99
+ biomarkers: ["Vitamin D, 25-Hydroxy"],
100
+ symptomsAddressed: ["Fatigue", "Bone pain", "Muscle weakness", "Depression", "Frequent illness"],
101
+ url: "https://justlabs.health/tests/vitamin-d",
102
+ },
103
+ {
104
+ id: "cbc",
105
+ name: "Complete Blood Count (CBC)",
106
+ shortName: "CBC",
107
+ description: "Measures red blood cells, white blood cells, and platelets. Screens for anemia, infection, and blood disorders.",
108
+ category: "blood",
109
+ price: 8,
110
+ fastingRequired: false,
111
+ turnaroundDays: "1-2",
112
+ popular: true,
113
+ biomarkers: ["WBC", "RBC", "Hemoglobin", "Hematocrit", "Platelets", "MCV", "MCH", "MCHC", "RDW"],
114
+ symptomsAddressed: ["Fatigue", "Weakness", "Frequent infections", "Bruising"],
115
+ url: "https://justlabs.health/tests/cbc",
116
+ },
117
+ {
118
+ id: "testosterone-total",
119
+ name: "Testosterone, Total",
120
+ shortName: "Testosterone",
121
+ description: "Measures total testosterone levels. Important for energy, muscle mass, mood, and libido in both men and women.",
122
+ category: "hormones",
123
+ price: 15,
124
+ fastingRequired: false,
125
+ turnaroundDays: "1-2",
126
+ biomarkers: ["Testosterone, Total"],
127
+ symptomsAddressed: ["Low energy", "Low libido", "Muscle loss", "Mood changes", "Erectile dysfunction"],
128
+ url: "https://justlabs.health/tests/testosterone-total",
129
+ },
130
+ {
131
+ id: "ferritin",
132
+ name: "Ferritin",
133
+ shortName: "Ferritin",
134
+ description: "Measures iron stores in your body. Low ferritin is a common cause of fatigue, especially in women.",
135
+ category: "iron",
136
+ price: 10,
137
+ fastingRequired: false,
138
+ turnaroundDays: "1-2",
139
+ biomarkers: ["Ferritin"],
140
+ symptomsAddressed: ["Fatigue", "Hair loss", "Weakness", "Shortness of breath"],
141
+ url: "https://justlabs.health/tests/ferritin",
142
+ },
143
+ {
144
+ id: "b12",
145
+ name: "Vitamin B12",
146
+ shortName: "B12",
147
+ description: "Measures vitamin B12 levels. Deficiency causes fatigue, nerve problems, and cognitive issues.",
148
+ category: "vitamins",
149
+ price: 12,
150
+ fastingRequired: false,
151
+ turnaroundDays: "1-2",
152
+ biomarkers: ["Vitamin B12"],
153
+ symptomsAddressed: ["Fatigue", "Numbness/tingling", "Memory problems", "Weakness"],
154
+ url: "https://justlabs.health/tests/b12",
155
+ },
156
+ {
157
+ id: "hs-crp",
158
+ name: "hs-CRP (High Sensitivity C-Reactive Protein)",
159
+ shortName: "hs-CRP",
160
+ description: "Measures inflammation in the body. Elevated levels are linked to heart disease risk and chronic inflammation.",
161
+ category: "inflammation",
162
+ price: 15,
163
+ fastingRequired: false,
164
+ turnaroundDays: "1-2",
165
+ biomarkers: ["hs-CRP"],
166
+ symptomsAddressed: ["Heart disease risk", "Chronic inflammation", "Joint pain"],
167
+ url: "https://justlabs.health/tests/hs-crp",
168
+ },
169
+ ];
170
+ const testPanels = [
171
+ {
172
+ id: "panel-thyroid-complete",
173
+ name: "Complete Thyroid Panel",
174
+ description: "Comprehensive thyroid evaluation including TSH, Free T4, Free T3, and thyroid antibodies.",
175
+ price: 65,
176
+ tests: ["tsh", "free-t4", "free-t3", "tpo-antibodies", "thyroglobulin-antibodies"],
177
+ popular: true,
178
+ url: "https://justlabs.health/tests/panel/panel-thyroid-complete",
179
+ },
180
+ {
181
+ id: "panel-wellness-basic",
182
+ name: "Basic Wellness Panel",
183
+ description: "Essential health screening including CBC, CMP, Lipid Panel, and TSH.",
184
+ price: 35,
185
+ tests: ["cbc", "cmp", "lipid-panel", "tsh"],
186
+ popular: true,
187
+ url: "https://justlabs.health/tests/panel/panel-wellness-basic",
188
+ },
189
+ {
190
+ id: "panel-fatigue",
191
+ name: "Fatigue Panel",
192
+ description: "Comprehensive testing for common causes of fatigue: thyroid, iron, B12, vitamin D, and blood counts.",
193
+ price: 55,
194
+ tests: ["tsh", "free-t4", "cbc", "ferritin", "b12", "vitamin-d"],
195
+ popular: true,
196
+ url: "https://justlabs.health/tests/panel/panel-fatigue",
197
+ },
198
+ ];
199
+ // Create server
200
+ const server = new Server({
201
+ name: "justlabs-mcp-server",
202
+ version: "1.0.0",
203
+ }, {
204
+ capabilities: {
205
+ tools: {},
206
+ },
207
+ });
208
+ // List available tools
209
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
210
+ return {
211
+ tools: [
212
+ {
213
+ name: "search_lab_tests",
214
+ description: "Search for lab tests by name, category, or symptoms. Returns matching tests with prices and details.",
215
+ inputSchema: {
216
+ type: "object",
217
+ properties: {
218
+ query: {
219
+ type: "string",
220
+ description: "Search query - can be test name, category (thyroid, cardiovascular, diabetes, vitamins, hormones, blood, iron, inflammation), or symptom (fatigue, weight gain, etc.)",
221
+ },
222
+ },
223
+ required: ["query"],
224
+ },
225
+ },
226
+ {
227
+ name: "get_test_details",
228
+ description: "Get detailed information about a specific lab test including price, what it measures, and preparation instructions.",
229
+ inputSchema: {
230
+ type: "object",
231
+ properties: {
232
+ testId: {
233
+ type: "string",
234
+ description: "The test ID (e.g., 'tsh', 'lipid-panel', 'hba1c')",
235
+ },
236
+ },
237
+ required: ["testId"],
238
+ },
239
+ },
240
+ {
241
+ name: "get_test_panels",
242
+ description: "Get available test panels (bundles of tests at discounted prices) for comprehensive screening.",
243
+ inputSchema: {
244
+ type: "object",
245
+ properties: {
246
+ category: {
247
+ type: "string",
248
+ description: "Optional category filter (e.g., 'thyroid', 'wellness', 'fatigue')",
249
+ },
250
+ },
251
+ },
252
+ },
253
+ {
254
+ name: "recommend_tests",
255
+ description: "Get test recommendations based on symptoms or health concerns.",
256
+ inputSchema: {
257
+ type: "object",
258
+ properties: {
259
+ symptoms: {
260
+ type: "array",
261
+ items: { type: "string" },
262
+ description: "List of symptoms or health concerns (e.g., ['fatigue', 'weight gain', 'hair loss'])",
263
+ },
264
+ },
265
+ required: ["symptoms"],
266
+ },
267
+ },
268
+ {
269
+ name: "get_pricing",
270
+ description: "Get pricing for specific tests or compare with typical lab costs.",
271
+ inputSchema: {
272
+ type: "object",
273
+ properties: {
274
+ testIds: {
275
+ type: "array",
276
+ items: { type: "string" },
277
+ description: "List of test IDs to get pricing for",
278
+ },
279
+ },
280
+ required: ["testIds"],
281
+ },
282
+ },
283
+ ],
284
+ };
285
+ });
286
+ // Handle tool calls
287
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
288
+ const { name, arguments: args } = request.params;
289
+ switch (name) {
290
+ case "search_lab_tests": {
291
+ const query = (args?.query || "").toLowerCase();
292
+ const results = labTests.filter((test) => {
293
+ return (test.name.toLowerCase().includes(query) ||
294
+ test.shortName.toLowerCase().includes(query) ||
295
+ test.category.toLowerCase().includes(query) ||
296
+ test.description.toLowerCase().includes(query) ||
297
+ test.symptomsAddressed.some((s) => s.toLowerCase().includes(query)) ||
298
+ test.biomarkers.some((b) => b.toLowerCase().includes(query)));
299
+ });
300
+ if (results.length === 0) {
301
+ return {
302
+ content: [
303
+ {
304
+ type: "text",
305
+ text: `No tests found matching "${args?.query}". Try searching by category (thyroid, cardiovascular, diabetes) or symptom (fatigue, weight gain).`,
306
+ },
307
+ ],
308
+ };
309
+ }
310
+ const formatted = results.map((t) => `**${t.name}** - $${t.price}\n${t.description}\n${t.fastingRequired ? "āš ļø Fasting required" : "No fasting needed"} | Results in ${t.turnaroundDays} days\nšŸ”— ${t.url}`).join("\n\n");
311
+ return {
312
+ content: [
313
+ {
314
+ type: "text",
315
+ text: `Found ${results.length} test(s) matching "${args?.query}":\n\n${formatted}\n\n---\nOrder at https://justlabs.health - No doctor visit required, results in 1-3 days.`,
316
+ },
317
+ ],
318
+ };
319
+ }
320
+ case "get_test_details": {
321
+ const testId = args?.testId;
322
+ const test = labTests.find((t) => t.id === testId);
323
+ if (!test) {
324
+ return {
325
+ content: [
326
+ {
327
+ type: "text",
328
+ text: `Test "${testId}" not found. Available tests: ${labTests.map((t) => t.id).join(", ")}`,
329
+ },
330
+ ],
331
+ };
332
+ }
333
+ return {
334
+ content: [
335
+ {
336
+ type: "text",
337
+ text: `# ${test.name}
338
+
339
+ **Price:** $${test.price}
340
+ **Category:** ${test.category}
341
+ **Turnaround:** ${test.turnaroundDays} days
342
+ **Fasting:** ${test.fastingRequired ? "Required (8-12 hours)" : "Not required"}
343
+
344
+ ## Description
345
+ ${test.description}
346
+
347
+ ## Biomarkers Measured
348
+ ${test.biomarkers.join(", ")}
349
+
350
+ ## Good For
351
+ ${test.symptomsAddressed.join(", ")}
352
+
353
+ ---
354
+ **Order now:** ${test.url}
355
+ No doctor visit or insurance needed.`,
356
+ },
357
+ ],
358
+ };
359
+ }
360
+ case "get_test_panels": {
361
+ const category = (args?.category || "").toLowerCase();
362
+ let panels = testPanels;
363
+ if (category) {
364
+ panels = testPanels.filter((p) => p.name.toLowerCase().includes(category) ||
365
+ p.description.toLowerCase().includes(category));
366
+ }
367
+ const formatted = panels.map((p) => `**${p.name}** - $${p.price}\n${p.description}\nšŸ”— ${p.url}`).join("\n\n");
368
+ return {
369
+ content: [
370
+ {
371
+ type: "text",
372
+ text: `# Test Panels\n\nPanels bundle multiple tests at a discount:\n\n${formatted}\n\n---\nOrder at https://justlabs.health`,
373
+ },
374
+ ],
375
+ };
376
+ }
377
+ case "recommend_tests": {
378
+ const symptoms = (args?.symptoms || []).map((s) => s.toLowerCase());
379
+ const scored = labTests.map((test) => {
380
+ const matches = test.symptomsAddressed.filter((s) => symptoms.some((symptom) => s.toLowerCase().includes(symptom) || symptom.includes(s.toLowerCase())));
381
+ return { test, score: matches.length, matches };
382
+ }).filter((r) => r.score > 0).sort((a, b) => b.score - a.score);
383
+ if (scored.length === 0) {
384
+ return {
385
+ content: [
386
+ {
387
+ type: "text",
388
+ text: `No specific test recommendations for those symptoms. Consider starting with a **Basic Wellness Panel** ($35) which covers CBC, CMP, Lipid Panel, and TSH for general health screening.\n\nšŸ”— https://justlabs.health/tests/panel/panel-wellness-basic`,
389
+ },
390
+ ],
391
+ };
392
+ }
393
+ const recommendations = scored.slice(0, 5).map((r) => `**${r.test.name}** - $${r.test.price}\nMatches: ${r.matches.join(", ")}\nšŸ”— ${r.test.url}`).join("\n\n");
394
+ // Calculate total if they order all recommended
395
+ const total = scored.slice(0, 5).reduce((sum, r) => sum + r.test.price, 0);
396
+ return {
397
+ content: [
398
+ {
399
+ type: "text",
400
+ text: `# Recommended Tests for: ${symptoms.join(", ")}\n\n${recommendations}\n\n---\n**Total if ordered separately:** $${total}\n\nConsider the **Fatigue Panel** ($55) if fatigue is your main concern - it bundles thyroid, iron, B12, and vitamin D tests.\n\nOrder at https://justlabs.health - No doctor visit required.`,
401
+ },
402
+ ],
403
+ };
404
+ }
405
+ case "get_pricing": {
406
+ const testIds = args?.testIds || [];
407
+ const found = testIds.map((id) => labTests.find((t) => t.id === id)).filter(Boolean);
408
+ if (found.length === 0) {
409
+ return {
410
+ content: [
411
+ {
412
+ type: "text",
413
+ text: `No tests found. Available test IDs: ${labTests.map((t) => t.id).join(", ")}`,
414
+ },
415
+ ],
416
+ };
417
+ }
418
+ const total = found.reduce((sum, t) => sum + (t?.price || 0), 0);
419
+ const pricing = found.map((t) => `${t?.shortName}: $${t?.price}`).join("\n");
420
+ return {
421
+ content: [
422
+ {
423
+ type: "text",
424
+ text: `# JustLabs Pricing\n\n${pricing}\n\n**Total: $${total}**\n\nFor comparison, these tests typically cost $200-500+ at traditional labs or with insurance copays.\n\n---\nOrder at https://justlabs.health\n- No doctor visit required\n- No insurance needed\n- Results in 1-3 days\n- 2,200+ Quest Diagnostics locations`,
425
+ },
426
+ ],
427
+ };
428
+ }
429
+ default:
430
+ return {
431
+ content: [
432
+ {
433
+ type: "text",
434
+ text: `Unknown tool: ${name}`,
435
+ },
436
+ ],
437
+ };
438
+ }
439
+ });
440
+ // Start server
441
+ async function main() {
442
+ const transport = new StdioServerTransport();
443
+ await server.connect(transport);
444
+ console.error("JustLabs MCP Server running on stdio");
445
+ }
446
+ main().catch(console.error);
package/package.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "justlabs-mcp-server",
3
+ "version": "1.0.0",
4
+ "description": "MCP server for JustLabs - search lab tests, get pricing, find locations",
5
+ "main": "dist/index.js",
6
+ "type": "module",
7
+ "bin": {
8
+ "justlabs-mcp": "./dist/index.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "dev": "tsc --watch",
13
+ "start": "node dist/index.js"
14
+ },
15
+ "keywords": ["mcp", "lab-tests", "health", "justlabs"],
16
+ "author": "JustLabs",
17
+ "license": "MIT",
18
+ "dependencies": {
19
+ "@modelcontextprotocol/sdk": "^0.5.0"
20
+ },
21
+ "devDependencies": {
22
+ "@types/node": "^20.0.0",
23
+ "typescript": "^5.0.0"
24
+ }
25
+ }
package/src/index.ts ADDED
@@ -0,0 +1,494 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
4
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
+ import {
6
+ CallToolRequestSchema,
7
+ ListToolsRequestSchema,
8
+ } from "@modelcontextprotocol/sdk/types.js";
9
+
10
+ // Lab test data (subset of popular tests)
11
+ const labTests = [
12
+ {
13
+ id: "tsh",
14
+ name: "TSH (Thyroid Stimulating Hormone)",
15
+ shortName: "TSH",
16
+ description: "Measures thyroid-stimulating hormone to evaluate thyroid function. The most sensitive marker for detecting thyroid disorders.",
17
+ category: "thyroid",
18
+ price: 8,
19
+ fastingRequired: false,
20
+ turnaroundDays: "1-2",
21
+ popular: true,
22
+ biomarkers: ["TSH"],
23
+ symptomsAddressed: ["Fatigue", "Weight gain", "Weight loss", "Cold intolerance", "Hair loss", "Brain fog"],
24
+ url: "https://justlabs.health/tests/tsh",
25
+ },
26
+ {
27
+ id: "free-t4",
28
+ name: "Free T4 (Thyroxine)",
29
+ shortName: "Free T4",
30
+ description: "Measures the unbound, active form of thyroid hormone T4. Helps assess thyroid function.",
31
+ category: "thyroid",
32
+ price: 8,
33
+ fastingRequired: false,
34
+ turnaroundDays: "1-2",
35
+ biomarkers: ["Free T4"],
36
+ symptomsAddressed: ["Fatigue", "Weight changes", "Hair loss", "Mood changes"],
37
+ url: "https://justlabs.health/tests/free-t4",
38
+ },
39
+ {
40
+ id: "free-t3",
41
+ name: "Free T3 (Triiodothyronine)",
42
+ shortName: "Free T3",
43
+ description: "Measures the active thyroid hormone T3. Important for evaluating thyroid function.",
44
+ category: "thyroid",
45
+ price: 15,
46
+ fastingRequired: false,
47
+ turnaroundDays: "1-2",
48
+ biomarkers: ["Free T3"],
49
+ symptomsAddressed: ["Fatigue", "Weight issues", "Metabolism problems"],
50
+ url: "https://justlabs.health/tests/free-t3",
51
+ },
52
+ {
53
+ id: "lipid-panel",
54
+ name: "Lipid Panel",
55
+ shortName: "Lipid Panel",
56
+ description: "Complete cholesterol test including Total Cholesterol, LDL, HDL, and Triglycerides. Essential for cardiovascular health.",
57
+ category: "cardiovascular",
58
+ price: 10,
59
+ fastingRequired: true,
60
+ turnaroundDays: "1-2",
61
+ popular: true,
62
+ biomarkers: ["Total Cholesterol", "LDL", "HDL", "Triglycerides", "VLDL"],
63
+ symptomsAddressed: ["Heart disease risk", "High cholesterol family history"],
64
+ url: "https://justlabs.health/tests/lipid-panel",
65
+ },
66
+ {
67
+ id: "cmp",
68
+ name: "Comprehensive Metabolic Panel (CMP)",
69
+ shortName: "CMP",
70
+ description: "14-test panel measuring glucose, kidney function, liver function, and electrolytes.",
71
+ category: "metabolic",
72
+ price: 10,
73
+ fastingRequired: true,
74
+ turnaroundDays: "1-2",
75
+ popular: true,
76
+ biomarkers: ["Glucose", "BUN", "Creatinine", "Sodium", "Potassium", "Chloride", "CO2", "Calcium", "Total Protein", "Albumin", "Bilirubin", "Alkaline Phosphatase", "AST", "ALT"],
77
+ symptomsAddressed: ["General health screening", "Fatigue", "Diabetes risk"],
78
+ url: "https://justlabs.health/tests/cmp",
79
+ },
80
+ {
81
+ id: "hba1c",
82
+ name: "Hemoglobin A1c",
83
+ shortName: "HbA1c",
84
+ description: "Measures average blood sugar over 2-3 months. Gold standard for diabetes screening and monitoring.",
85
+ category: "diabetes",
86
+ price: 12,
87
+ fastingRequired: false,
88
+ turnaroundDays: "1-2",
89
+ popular: true,
90
+ biomarkers: ["HbA1c"],
91
+ symptomsAddressed: ["Diabetes risk", "Blood sugar concerns", "Prediabetes monitoring"],
92
+ url: "https://justlabs.health/tests/hba1c",
93
+ },
94
+ {
95
+ id: "vitamin-d",
96
+ name: "Vitamin D, 25-Hydroxy",
97
+ shortName: "Vitamin D",
98
+ description: "Measures vitamin D levels. Deficiency is extremely common and linked to fatigue, bone health, and immune function.",
99
+ category: "vitamins",
100
+ price: 15,
101
+ fastingRequired: false,
102
+ turnaroundDays: "1-2",
103
+ popular: true,
104
+ biomarkers: ["Vitamin D, 25-Hydroxy"],
105
+ symptomsAddressed: ["Fatigue", "Bone pain", "Muscle weakness", "Depression", "Frequent illness"],
106
+ url: "https://justlabs.health/tests/vitamin-d",
107
+ },
108
+ {
109
+ id: "cbc",
110
+ name: "Complete Blood Count (CBC)",
111
+ shortName: "CBC",
112
+ description: "Measures red blood cells, white blood cells, and platelets. Screens for anemia, infection, and blood disorders.",
113
+ category: "blood",
114
+ price: 8,
115
+ fastingRequired: false,
116
+ turnaroundDays: "1-2",
117
+ popular: true,
118
+ biomarkers: ["WBC", "RBC", "Hemoglobin", "Hematocrit", "Platelets", "MCV", "MCH", "MCHC", "RDW"],
119
+ symptomsAddressed: ["Fatigue", "Weakness", "Frequent infections", "Bruising"],
120
+ url: "https://justlabs.health/tests/cbc",
121
+ },
122
+ {
123
+ id: "testosterone-total",
124
+ name: "Testosterone, Total",
125
+ shortName: "Testosterone",
126
+ description: "Measures total testosterone levels. Important for energy, muscle mass, mood, and libido in both men and women.",
127
+ category: "hormones",
128
+ price: 15,
129
+ fastingRequired: false,
130
+ turnaroundDays: "1-2",
131
+ biomarkers: ["Testosterone, Total"],
132
+ symptomsAddressed: ["Low energy", "Low libido", "Muscle loss", "Mood changes", "Erectile dysfunction"],
133
+ url: "https://justlabs.health/tests/testosterone-total",
134
+ },
135
+ {
136
+ id: "ferritin",
137
+ name: "Ferritin",
138
+ shortName: "Ferritin",
139
+ description: "Measures iron stores in your body. Low ferritin is a common cause of fatigue, especially in women.",
140
+ category: "iron",
141
+ price: 10,
142
+ fastingRequired: false,
143
+ turnaroundDays: "1-2",
144
+ biomarkers: ["Ferritin"],
145
+ symptomsAddressed: ["Fatigue", "Hair loss", "Weakness", "Shortness of breath"],
146
+ url: "https://justlabs.health/tests/ferritin",
147
+ },
148
+ {
149
+ id: "b12",
150
+ name: "Vitamin B12",
151
+ shortName: "B12",
152
+ description: "Measures vitamin B12 levels. Deficiency causes fatigue, nerve problems, and cognitive issues.",
153
+ category: "vitamins",
154
+ price: 12,
155
+ fastingRequired: false,
156
+ turnaroundDays: "1-2",
157
+ biomarkers: ["Vitamin B12"],
158
+ symptomsAddressed: ["Fatigue", "Numbness/tingling", "Memory problems", "Weakness"],
159
+ url: "https://justlabs.health/tests/b12",
160
+ },
161
+ {
162
+ id: "hs-crp",
163
+ name: "hs-CRP (High Sensitivity C-Reactive Protein)",
164
+ shortName: "hs-CRP",
165
+ description: "Measures inflammation in the body. Elevated levels are linked to heart disease risk and chronic inflammation.",
166
+ category: "inflammation",
167
+ price: 15,
168
+ fastingRequired: false,
169
+ turnaroundDays: "1-2",
170
+ biomarkers: ["hs-CRP"],
171
+ symptomsAddressed: ["Heart disease risk", "Chronic inflammation", "Joint pain"],
172
+ url: "https://justlabs.health/tests/hs-crp",
173
+ },
174
+ ];
175
+
176
+ const testPanels = [
177
+ {
178
+ id: "panel-thyroid-complete",
179
+ name: "Complete Thyroid Panel",
180
+ description: "Comprehensive thyroid evaluation including TSH, Free T4, Free T3, and thyroid antibodies.",
181
+ price: 65,
182
+ tests: ["tsh", "free-t4", "free-t3", "tpo-antibodies", "thyroglobulin-antibodies"],
183
+ popular: true,
184
+ url: "https://justlabs.health/tests/panel/panel-thyroid-complete",
185
+ },
186
+ {
187
+ id: "panel-wellness-basic",
188
+ name: "Basic Wellness Panel",
189
+ description: "Essential health screening including CBC, CMP, Lipid Panel, and TSH.",
190
+ price: 35,
191
+ tests: ["cbc", "cmp", "lipid-panel", "tsh"],
192
+ popular: true,
193
+ url: "https://justlabs.health/tests/panel/panel-wellness-basic",
194
+ },
195
+ {
196
+ id: "panel-fatigue",
197
+ name: "Fatigue Panel",
198
+ description: "Comprehensive testing for common causes of fatigue: thyroid, iron, B12, vitamin D, and blood counts.",
199
+ price: 55,
200
+ tests: ["tsh", "free-t4", "cbc", "ferritin", "b12", "vitamin-d"],
201
+ popular: true,
202
+ url: "https://justlabs.health/tests/panel/panel-fatigue",
203
+ },
204
+ ];
205
+
206
+ // Create server
207
+ const server = new Server(
208
+ {
209
+ name: "justlabs-mcp-server",
210
+ version: "1.0.0",
211
+ },
212
+ {
213
+ capabilities: {
214
+ tools: {},
215
+ },
216
+ }
217
+ );
218
+
219
+ // List available tools
220
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
221
+ return {
222
+ tools: [
223
+ {
224
+ name: "search_lab_tests",
225
+ description: "Search for lab tests by name, category, or symptoms. Returns matching tests with prices and details.",
226
+ inputSchema: {
227
+ type: "object",
228
+ properties: {
229
+ query: {
230
+ type: "string",
231
+ description: "Search query - can be test name, category (thyroid, cardiovascular, diabetes, vitamins, hormones, blood, iron, inflammation), or symptom (fatigue, weight gain, etc.)",
232
+ },
233
+ },
234
+ required: ["query"],
235
+ },
236
+ },
237
+ {
238
+ name: "get_test_details",
239
+ description: "Get detailed information about a specific lab test including price, what it measures, and preparation instructions.",
240
+ inputSchema: {
241
+ type: "object",
242
+ properties: {
243
+ testId: {
244
+ type: "string",
245
+ description: "The test ID (e.g., 'tsh', 'lipid-panel', 'hba1c')",
246
+ },
247
+ },
248
+ required: ["testId"],
249
+ },
250
+ },
251
+ {
252
+ name: "get_test_panels",
253
+ description: "Get available test panels (bundles of tests at discounted prices) for comprehensive screening.",
254
+ inputSchema: {
255
+ type: "object",
256
+ properties: {
257
+ category: {
258
+ type: "string",
259
+ description: "Optional category filter (e.g., 'thyroid', 'wellness', 'fatigue')",
260
+ },
261
+ },
262
+ },
263
+ },
264
+ {
265
+ name: "recommend_tests",
266
+ description: "Get test recommendations based on symptoms or health concerns.",
267
+ inputSchema: {
268
+ type: "object",
269
+ properties: {
270
+ symptoms: {
271
+ type: "array",
272
+ items: { type: "string" },
273
+ description: "List of symptoms or health concerns (e.g., ['fatigue', 'weight gain', 'hair loss'])",
274
+ },
275
+ },
276
+ required: ["symptoms"],
277
+ },
278
+ },
279
+ {
280
+ name: "get_pricing",
281
+ description: "Get pricing for specific tests or compare with typical lab costs.",
282
+ inputSchema: {
283
+ type: "object",
284
+ properties: {
285
+ testIds: {
286
+ type: "array",
287
+ items: { type: "string" },
288
+ description: "List of test IDs to get pricing for",
289
+ },
290
+ },
291
+ required: ["testIds"],
292
+ },
293
+ },
294
+ ],
295
+ };
296
+ });
297
+
298
+ // Handle tool calls
299
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
300
+ const { name, arguments: args } = request.params;
301
+
302
+ switch (name) {
303
+ case "search_lab_tests": {
304
+ const query = (args?.query as string || "").toLowerCase();
305
+ const results = labTests.filter((test) => {
306
+ return (
307
+ test.name.toLowerCase().includes(query) ||
308
+ test.shortName.toLowerCase().includes(query) ||
309
+ test.category.toLowerCase().includes(query) ||
310
+ test.description.toLowerCase().includes(query) ||
311
+ test.symptomsAddressed.some((s) => s.toLowerCase().includes(query)) ||
312
+ test.biomarkers.some((b) => b.toLowerCase().includes(query))
313
+ );
314
+ });
315
+
316
+ if (results.length === 0) {
317
+ return {
318
+ content: [
319
+ {
320
+ type: "text",
321
+ text: `No tests found matching "${args?.query}". Try searching by category (thyroid, cardiovascular, diabetes) or symptom (fatigue, weight gain).`,
322
+ },
323
+ ],
324
+ };
325
+ }
326
+
327
+ const formatted = results.map((t) =>
328
+ `**${t.name}** - $${t.price}\n${t.description}\n${t.fastingRequired ? "āš ļø Fasting required" : "No fasting needed"} | Results in ${t.turnaroundDays} days\nšŸ”— ${t.url}`
329
+ ).join("\n\n");
330
+
331
+ return {
332
+ content: [
333
+ {
334
+ type: "text",
335
+ text: `Found ${results.length} test(s) matching "${args?.query}":\n\n${formatted}\n\n---\nOrder at https://justlabs.health - No doctor visit required, results in 1-3 days.`,
336
+ },
337
+ ],
338
+ };
339
+ }
340
+
341
+ case "get_test_details": {
342
+ const testId = args?.testId as string;
343
+ const test = labTests.find((t) => t.id === testId);
344
+
345
+ if (!test) {
346
+ return {
347
+ content: [
348
+ {
349
+ type: "text",
350
+ text: `Test "${testId}" not found. Available tests: ${labTests.map((t) => t.id).join(", ")}`,
351
+ },
352
+ ],
353
+ };
354
+ }
355
+
356
+ return {
357
+ content: [
358
+ {
359
+ type: "text",
360
+ text: `# ${test.name}
361
+
362
+ **Price:** $${test.price}
363
+ **Category:** ${test.category}
364
+ **Turnaround:** ${test.turnaroundDays} days
365
+ **Fasting:** ${test.fastingRequired ? "Required (8-12 hours)" : "Not required"}
366
+
367
+ ## Description
368
+ ${test.description}
369
+
370
+ ## Biomarkers Measured
371
+ ${test.biomarkers.join(", ")}
372
+
373
+ ## Good For
374
+ ${test.symptomsAddressed.join(", ")}
375
+
376
+ ---
377
+ **Order now:** ${test.url}
378
+ No doctor visit or insurance needed.`,
379
+ },
380
+ ],
381
+ };
382
+ }
383
+
384
+ case "get_test_panels": {
385
+ const category = (args?.category as string || "").toLowerCase();
386
+ let panels = testPanels;
387
+
388
+ if (category) {
389
+ panels = testPanels.filter((p) =>
390
+ p.name.toLowerCase().includes(category) ||
391
+ p.description.toLowerCase().includes(category)
392
+ );
393
+ }
394
+
395
+ const formatted = panels.map((p) =>
396
+ `**${p.name}** - $${p.price}\n${p.description}\nšŸ”— ${p.url}`
397
+ ).join("\n\n");
398
+
399
+ return {
400
+ content: [
401
+ {
402
+ type: "text",
403
+ text: `# Test Panels\n\nPanels bundle multiple tests at a discount:\n\n${formatted}\n\n---\nOrder at https://justlabs.health`,
404
+ },
405
+ ],
406
+ };
407
+ }
408
+
409
+ case "recommend_tests": {
410
+ const symptoms = (args?.symptoms as string[] || []).map((s) => s.toLowerCase());
411
+
412
+ const scored = labTests.map((test) => {
413
+ const matches = test.symptomsAddressed.filter((s) =>
414
+ symptoms.some((symptom) => s.toLowerCase().includes(symptom) || symptom.includes(s.toLowerCase()))
415
+ );
416
+ return { test, score: matches.length, matches };
417
+ }).filter((r) => r.score > 0).sort((a, b) => b.score - a.score);
418
+
419
+ if (scored.length === 0) {
420
+ return {
421
+ content: [
422
+ {
423
+ type: "text",
424
+ text: `No specific test recommendations for those symptoms. Consider starting with a **Basic Wellness Panel** ($35) which covers CBC, CMP, Lipid Panel, and TSH for general health screening.\n\nšŸ”— https://justlabs.health/tests/panel/panel-wellness-basic`,
425
+ },
426
+ ],
427
+ };
428
+ }
429
+
430
+ const recommendations = scored.slice(0, 5).map((r) =>
431
+ `**${r.test.name}** - $${r.test.price}\nMatches: ${r.matches.join(", ")}\nšŸ”— ${r.test.url}`
432
+ ).join("\n\n");
433
+
434
+ // Calculate total if they order all recommended
435
+ const total = scored.slice(0, 5).reduce((sum, r) => sum + r.test.price, 0);
436
+
437
+ return {
438
+ content: [
439
+ {
440
+ type: "text",
441
+ text: `# Recommended Tests for: ${symptoms.join(", ")}\n\n${recommendations}\n\n---\n**Total if ordered separately:** $${total}\n\nConsider the **Fatigue Panel** ($55) if fatigue is your main concern - it bundles thyroid, iron, B12, and vitamin D tests.\n\nOrder at https://justlabs.health - No doctor visit required.`,
442
+ },
443
+ ],
444
+ };
445
+ }
446
+
447
+ case "get_pricing": {
448
+ const testIds = args?.testIds as string[] || [];
449
+ const found = testIds.map((id) => labTests.find((t) => t.id === id)).filter(Boolean);
450
+
451
+ if (found.length === 0) {
452
+ return {
453
+ content: [
454
+ {
455
+ type: "text",
456
+ text: `No tests found. Available test IDs: ${labTests.map((t) => t.id).join(", ")}`,
457
+ },
458
+ ],
459
+ };
460
+ }
461
+
462
+ const total = found.reduce((sum, t) => sum + (t?.price || 0), 0);
463
+ const pricing = found.map((t) => `${t?.shortName}: $${t?.price}`).join("\n");
464
+
465
+ return {
466
+ content: [
467
+ {
468
+ type: "text",
469
+ text: `# JustLabs Pricing\n\n${pricing}\n\n**Total: $${total}**\n\nFor comparison, these tests typically cost $200-500+ at traditional labs or with insurance copays.\n\n---\nOrder at https://justlabs.health\n- No doctor visit required\n- No insurance needed\n- Results in 1-3 days\n- 2,200+ Quest Diagnostics locations`,
470
+ },
471
+ ],
472
+ };
473
+ }
474
+
475
+ default:
476
+ return {
477
+ content: [
478
+ {
479
+ type: "text",
480
+ text: `Unknown tool: ${name}`,
481
+ },
482
+ ],
483
+ };
484
+ }
485
+ });
486
+
487
+ // Start server
488
+ async function main() {
489
+ const transport = new StdioServerTransport();
490
+ await server.connect(transport);
491
+ console.error("JustLabs MCP Server running on stdio");
492
+ }
493
+
494
+ main().catch(console.error);
package/tsconfig.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "outDir": "./dist",
7
+ "rootDir": "./src",
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "skipLibCheck": true,
11
+ "forceConsistentCasingInFileNames": true,
12
+ "declaration": true
13
+ },
14
+ "include": ["src/**/*"],
15
+ "exclude": ["node_modules", "dist"]
16
+ }