truthstack-mcp 2.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.
@@ -0,0 +1,160 @@
1
+ # TruthStack Discovery Quests — Tier 0 (Distribution)
2
+ ## Week 1 Execution Checklist
3
+
4
+ **Philosophy:** The quest isn't just "enrich the database" — it's "go get us discovered."
5
+ Discovery → Adoption → Contribution → Enrichment. You can't skip steps.
6
+
7
+ ---
8
+
9
+ ## Category 1: MCP Directory Submissions
10
+
11
+ Submit TruthStack MCP server to every directory with rich metadata, health/supplement tags,
12
+ example prompts, and a link to the GitHub repo.
13
+
14
+ - [ ] **Official MCP Registry** — registry.modelcontextprotocol.io
15
+ - Tags: health, supplements, drug-interactions, safety, pharmacology
16
+ - Description: "First supplement-drug interaction safety tool for AI agents"
17
+
18
+ - [ ] **GitHub modelcontextprotocol/servers** — Open PR to add to official list
19
+ - Category: Health & Safety
20
+ - Include: description, 5 tools listed, example usage
21
+
22
+ - [ ] **Glama.ai** — MCP server directory
23
+
24
+ - [ ] **MCPServerHub** — Community directory
25
+
26
+ - [ ] **Awesome MCP Servers** — GitHub awesome list (multiple repos)
27
+ - Search GitHub for "awesome-mcp-servers" — submit to all active ones
28
+
29
+ - [ ] **Smithery** — MCP server registry
30
+
31
+ - [ ] **Kong MCP** — If directory exists by launch
32
+
33
+ **Target: 5-7 directory listings in week 1**
34
+
35
+ ---
36
+
37
+ ## Category 2: Framework Presence
38
+
39
+ Working code examples posted where agent developers find tools.
40
+
41
+ - [ ] **GitHub repo: truthstack-example-health-agent**
42
+ - Claude Desktop config + working demo
43
+ - LangChain tool wrapper with example script
44
+ - README with setup in <5 minutes
45
+
46
+ - [ ] **LangChain community** — Post example in LangChain Discord/forums
47
+ - Title: "Supplement safety tool for health agents"
48
+ - Include working code snippet
49
+
50
+ - [ ] **CrewAI community** — Post example agent that uses TruthStack
51
+ - "Health Safety Agent" that checks stacks before recommending
52
+
53
+ - [ ] **AutoGen/LlamaIndex** — GitHub gist with integration example (week 2)
54
+
55
+ **Target: 3 framework examples published by end of week 2**
56
+
57
+ ---
58
+
59
+ ## Category 3: GitHub Outreach
60
+
61
+ Find health AI agent repos and suggest TruthStack integration.
62
+
63
+ - [ ] Search GitHub: "health agent" "supplement" — find active repos
64
+ - [ ] Search GitHub: "langchain health" "crewai health" — find health-focused agent projects
65
+ - [ ] Search GitHub: "medication" "drug interaction" "ai agent" — find adjacent projects
66
+ - [ ] For each active repo (>10 stars, recent commits):
67
+ - Open a constructive issue: "Supplement safety integration available"
68
+ - Include: what TruthStack does, how to integrate (3 lines), link to example repo
69
+ - **DO NOT spam.** Only repos where supplement safety is genuinely useful.
70
+
71
+ **Target: 5-10 constructive GitHub issues/PRs opened**
72
+
73
+ ---
74
+
75
+ ## Category 4: Content Seeding
76
+
77
+ Technical posts that show up in developer searches.
78
+
79
+ - [ ] **Blog post:** "Why your health AI agent needs a real interaction database"
80
+ - Host on truthstack.co/blog or Medium
81
+ - Include the demo contrast (LLM vs API)
82
+ - Target keywords: "supplement drug interaction API", "health AI agent safety"
83
+
84
+ - [ ] **dev.to post:** Technical walkthrough of MCP integration
85
+ - Tags: #ai #health #mcp #agents
86
+
87
+ - [ ] **Reddit r/AI_Agents** — Share the MCP server with context
88
+ - Not promotional — frame as "I built this, feedback welcome"
89
+
90
+ - [ ] **Hacker News** — "Show HN: Supplement safety API for AI agents"
91
+ - Best timing: Tuesday or Wednesday morning US time
92
+ - Lead with the demo contrast (LLM hallucination vs structured API)
93
+
94
+ - [ ] **X/Twitter thread:** "We built the first supplement safety MCP server. Here's why LLMs can't do this alone."
95
+ - Tag: @AnthropicAI, @LangChainAI, MCP community accounts
96
+ - Include screenshot of Claude Desktop using TruthStack tools
97
+
98
+ - [ ] **LinkedIn post:** Same angle, targeting health tech founders and VCs
99
+
100
+ **Target: 3-5 posts published by end of week 2**
101
+
102
+ ---
103
+
104
+ ## Category 5: Community Infiltration
105
+
106
+ Join where health AI builders already hang out.
107
+
108
+ - [ ] **Health AI Discord servers** — Search Disboard for health AI communities
109
+ - [ ] **LangChain Discord** — #showcase or #tools channel
110
+ - [ ] **Anthropic Discord** — #mcp-servers channel (if exists)
111
+ - [ ] **Digital health Slack groups** — Rock Health, Health 2.0, etc.
112
+ - [ ] **Product Hunt upcoming** — Set up the PH page now, schedule for weeks 8-10
113
+
114
+ **Target: 3 communities joined, at least 1 meaningful post in each**
115
+
116
+ ---
117
+
118
+ ## Tracking
119
+
120
+ | Quest | Status | Date Completed | Notes |
121
+ |-------|--------|----------------|-------|
122
+ | Official MCP Registry | | | |
123
+ | GitHub MCP servers PR | | | |
124
+ | Glama.ai | | | |
125
+ | MCPServerHub | | | |
126
+ | Awesome MCP lists | | | |
127
+ | Smithery | | | |
128
+ | GitHub example repo | | | |
129
+ | LangChain example | | | |
130
+ | CrewAI example | | | |
131
+ | Blog post | | | |
132
+ | dev.to post | | | |
133
+ | Reddit post | | | |
134
+ | HN Show HN | | | |
135
+ | X thread | | | |
136
+ | LinkedIn post | | | |
137
+ | GitHub outreach (5-10) | | | |
138
+ | Community joins (3+) | | | |
139
+
140
+ ---
141
+
142
+ ## Week 1 Target: 20 discovery touchpoints
143
+
144
+ If you hit 20 places where a health AI builder can stumble onto TruthStack without
145
+ you doing cold outreach, you've given the flywheel its first real spin.
146
+
147
+ ## Phase 2 (Weeks 5-8): Adoption Quests
148
+ Agents already using the API get nudged to:
149
+ - Report unresolved compound names
150
+ - Test edge cases and provide feedback
151
+ - Share their integration publicly
152
+
153
+ ## Phase 3 (Weeks 9-12): Enrichment Quests
154
+ Agents contribute real data:
155
+ - New aliases from user input
156
+ - Label scan extractions
157
+ - Stack patterns and outcomes
158
+ - PubMed article summaries
159
+
160
+ **Discovery first. Contribution follows usage.**
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 TruthStack1
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,172 @@
1
+ # TruthStack MCP Server
2
+
3
+ **The first supplement-drug interaction safety tool for AI agents.**
4
+
5
+ TruthStack provides structured, evidence-based supplement safety intelligence via the [Model Context Protocol](https://modelcontextprotocol.io). Instead of relying on LLM training data that hallucinates safety information, your agent calls TruthStack for deterministic, cited risk assessments.
6
+
7
+ ## Why This Exists
8
+
9
+ LLMs confidently say "ashwagandha is generally safe with sertraline." TruthStack's API returns **MODERATE RISK** with 25 FDA adverse event reports and CYP3A4 pathway conflict data. That gap kills people.
10
+
11
+ ## 5 Tools
12
+
13
+ | Tool | What It Does | When to Use |
14
+ |------|-------------|-------------|
15
+ | `check_interactions` | Supplements + medications → risk level, FAERS signals, CYP conflicts | User mentions supplements + meds together |
16
+ | `search_compounds` | Fuzzy name search (584 aliases, handles misspellings/brands) | Need to resolve messy input ("mag gly", "KSM-66") |
17
+ | `get_compound_info` | Full compound profile + all interactions | Deep dive on a specific supplement |
18
+ | `explain_interaction` | Human-readable WHY — mechanism, severity, evidence summary | Need to explain risk to a user |
19
+ | `get_evidence` | Raw evidence: FAERS counts, CYP data, research grades, label warnings | Need to cite sources or provide provenance |
20
+
21
+ ## Data Sources
22
+
23
+ - **FDA FAERS** — 805 adverse event signals from real-world pharmacovigilance
24
+ - **FDA Drug Labels** — CYP450 pathways, contraindications, botanical warnings
25
+ - **PubMed/ClinicalTrials.gov** — 220 research findings with evidence grading
26
+ - **584 compound aliases** — misspellings, brand names, abbreviations, product forms
27
+
28
+ ## Quick Start
29
+
30
+ ### 1. Get API Key
31
+
32
+ Contact [chris@truthstack.co](mailto:chris@truthstack.co) or visit [truthstack.co](https://truthstack.co)
33
+
34
+ ### 2. Install
35
+
36
+ ```bash
37
+ git clone https://github.com/truthstack/truthstack-mcp.git
38
+ cd truthstack-mcp
39
+ npm install
40
+ ```
41
+
42
+ ### 3. Configure Claude Desktop
43
+
44
+ Edit `~/.claude/claude_desktop_config.json`:
45
+
46
+ ```json
47
+ {
48
+ "mcpServers": {
49
+ "truthstack": {
50
+ "command": "node",
51
+ "args": ["/path/to/truthstack-mcp/server.js"],
52
+ "env": {
53
+ "VAULT_API_URL": "https://api.truthstack.co",
54
+ "VAULT_API_KEY": "your-api-key"
55
+ }
56
+ }
57
+ }
58
+ }
59
+ ```
60
+
61
+ Restart Claude Desktop. You'll see TruthStack tools available in the tool picker.
62
+
63
+ ### 4. Test It
64
+
65
+ Ask Claude: *"I take ashwagandha, fish oil, and magnesium with sertraline. Is this safe?"*
66
+
67
+ Claude will call `check_interactions` and return a structured risk assessment with FDA adverse event data.
68
+
69
+ ## LangChain Integration
70
+
71
+ ```python
72
+ from langchain_community.tools import MCPTool
73
+
74
+ # If using MCP adapter
75
+ truthstack = MCPTool(server_path="./server.js", env={
76
+ "VAULT_API_URL": "https://api.truthstack.co",
77
+ "VAULT_API_KEY": "your-key"
78
+ })
79
+
80
+ # Or call the REST API directly
81
+ import requests
82
+
83
+ response = requests.post(
84
+ "https://api.truthstack.co/api/interactions/check",
85
+ headers={"X-API-Key": "your-key"},
86
+ json={
87
+ "supplements": ["ashwagandha", "fish oil", "magnesium"],
88
+ "medications": ["sertraline"]
89
+ }
90
+ )
91
+ print(response.json())
92
+ ```
93
+
94
+ ## REST API Fallback
95
+
96
+ Every MCP tool maps to a REST endpoint:
97
+
98
+ | MCP Tool | REST Endpoint |
99
+ |----------|---------------|
100
+ | `check_interactions` | `POST /api/interactions/check` |
101
+ | `search_compounds` | `GET /api/compounds/search?q={query}` |
102
+ | `get_compound_info` | `GET /api/compounds/{id}` + `GET /api/compounds/{id}/interactions` |
103
+ | `explain_interaction` | Composite (search + interactions + drug profile) |
104
+ | `get_evidence` | Composite (search + interactions + drug profile) |
105
+
106
+ Base URL: `https://api.truthstack.co`
107
+ Auth: `X-API-Key` header
108
+
109
+ ## Example Response
110
+
111
+ ```
112
+ User: "Is ashwagandha safe with sertraline?"
113
+
114
+ → check_interactions({
115
+ supplements: ["ashwagandha"],
116
+ medications: ["sertraline"]
117
+ })
118
+
119
+ → {
120
+ "risk_level": "MODERATE",
121
+ "drug_interactions": [{
122
+ "supplement": "ashwagandha",
123
+ "drug": "sertraline",
124
+ "severity": "MODERATE",
125
+ "source": "FDA FAERS",
126
+ "report_count": 25,
127
+ "description": "Pharmacovigilance signal — 25 serious adverse events reported"
128
+ }],
129
+ "cyp_pathway_conflicts": [{
130
+ "drug": "sertraline",
131
+ "supplement": "ashwagandha",
132
+ "shared_cyp_pathways": ["CYP3A4"]
133
+ }]
134
+ }
135
+ ```
136
+
137
+ Compare to raw LLM: *"Ashwagandha is generally considered safe and may complement sertraline for anxiety."*
138
+
139
+ ## System Message Template
140
+
141
+ If you're building a health agent, add this to your system prompt:
142
+
143
+ ```
144
+ You have access to TruthStack supplement safety tools. ALWAYS use check_interactions
145
+ before confirming any supplement is safe with a medication. Never rely on your training
146
+ data for drug-supplement interaction safety — use the structured API instead.
147
+
148
+ When reporting results:
149
+ - State the risk level clearly (CRITICAL/HIGH/MODERATE/LOW)
150
+ - Mention specific FAERS adverse event counts when available
151
+ - Note CYP pathway conflicts
152
+ - Always recommend consulting a healthcare provider for MODERATE+ risks
153
+ - Use explain_interaction when users ask "why is this risky?"
154
+ - Use get_evidence when users want to see the sources
155
+ ```
156
+
157
+ ## Contributing
158
+
159
+ We're looking for:
160
+ - **Integration partners** — building a health AI agent? Get free API access.
161
+ - **Compound contributions** — know of missing supplement aliases or interactions? Open an issue.
162
+ - **Framework examples** — help us add examples for CrewAI, AutoGen, LlamaIndex.
163
+
164
+ ## License
165
+
166
+ MIT
167
+
168
+ ## Contact
169
+
170
+ - **API access**: [chris@truthstack.co](mailto:chris@truthstack.co)
171
+ - **Website**: [truthstack.co](https://truthstack.co)
172
+ - **API docs**: [api.truthstack.co](https://api.truthstack.co)
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "truthstack-mcp",
3
+ "version": "2.1.0",
4
+ "description": "TruthStack MCP Server \u2014 Supplement-drug interaction safety intelligence for AI agents",
5
+ "type": "module",
6
+ "main": "server.js",
7
+ "scripts": {
8
+ "start": "node server.js"
9
+ },
10
+ "dependencies": {
11
+ "@modelcontextprotocol/sdk": "^1.0.0",
12
+ "zod": "^3.22.0"
13
+ },
14
+ "keywords": [
15
+ "mcp",
16
+ "supplements",
17
+ "drug-interactions",
18
+ "health",
19
+ "safety",
20
+ "ai-agents",
21
+ "truthstack"
22
+ ],
23
+ "author": "TruthStack Inc.",
24
+ "license": "MIT",
25
+ "bin": {
26
+ "truthstack-mcp": "./server.js"
27
+ },
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "https://github.com/TruthStack1/truthstack-mcp.git"
31
+ },
32
+ "homepage": "https://api.truthstack.co"
33
+ }
package/server.js ADDED
@@ -0,0 +1,142 @@
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
+
6
+ const VAULT_API_URL = process.env.VAULT_API_URL || "https://api.truthstack.co";
7
+ const VAULT_API_KEY = process.env.VAULT_API_KEY;
8
+ if (!VAULT_API_KEY) { console.error("ERROR: VAULT_API_KEY required"); process.exit(1); }
9
+
10
+ async function vaultFetch(path, options = {}) {
11
+ const r = await fetch(`${VAULT_API_URL}${path}`, { ...options, headers: { "X-API-Key": VAULT_API_KEY, "Content-Type": "application/json", ...options.headers } });
12
+ if (!r.ok) { const t = await r.text(); throw new Error(`Vault API error ${r.status}: ${t}`); }
13
+ return r.json();
14
+ }
15
+ async function searchCompounds(q, limit = 10) { return vaultFetch(`/api/compounds/search?q=${encodeURIComponent(q)}&limit=${limit}`); }
16
+ async function getCompound(id) { return vaultFetch(`/api/compounds/${encodeURIComponent(id)}`); }
17
+ async function getCompoundInteractions(id) { return vaultFetch(`/api/compounds/${encodeURIComponent(id)}/interactions`); }
18
+ async function checkInteractions(supps, meds) { return vaultFetch("/api/interactions/check", { method: "POST", body: JSON.stringify({ supplements: supps, medications: meds }) }); }
19
+ async function getDrugProfile(id) { return vaultFetch(`/api/drugs/${encodeURIComponent(id)}`); }
20
+
21
+ async function buildExplanation(supplementName, drugName) {
22
+ const sr = await searchCompounds(supplementName, 1);
23
+ const compound = sr?.results?.[0];
24
+ if (!compound) return { supplement: supplementName, drug: drugName, explanation: `Could not resolve "${supplementName}".`, severity: "UNKNOWN", confidence: "low" };
25
+ const compoundId = compound.compound_id;
26
+ const interactions = await getCompoundInteractions(compoundId);
27
+ const di = (interactions?.interactions || []).filter(i => i.target_id?.toLowerCase().includes(drugName.toLowerCase()) || i.target_name?.toLowerCase().includes(drugName.toLowerCase()));
28
+ let drugProfile = null;
29
+ try { drugProfile = await getDrugProfile(drugName.toLowerCase().replace(/\s+/g, "_")); } catch(e) {}
30
+ if (di.length === 0 && !drugProfile) return { supplement: supplementName, drug: drugName, resolved_compound: compoundId, explanation: `No known interactions found between ${compound.name} and ${drugName}. This does not guarantee safety.`, severity: "LOW", confidence: "low", evidence_count: 0 };
31
+ const faers = di.filter(i => i.source_origin === "OPENFDA");
32
+ const research = di.filter(i => i.source_origin !== "OPENFDA");
33
+ const totalFaers = faers.reduce((s, f) => s + (f.metadata?.report_count || 0), 0);
34
+ let severity = "LOW";
35
+ const sevs = di.map(i => i.severity);
36
+ if (sevs.includes("CRITICAL")) severity = "CRITICAL";
37
+ else if (sevs.includes("HIGH") || sevs.includes("MAJOR")) severity = "HIGH";
38
+ else if (sevs.includes("MODERATE")) severity = "MODERATE";
39
+ let cypMech = "";
40
+ if (drugProfile?.profile?.cyp_pathways) {
41
+ const cyps = drugProfile.profile.cyp_pathways;
42
+ const allDrug = [...(cyps.metabolized_by||[]),...(cyps.inhibits||[]),...(cyps.induces||[])];
43
+ const cd = await getCompound(compoundId);
44
+ const compCyps = cd?.compound?.data?.cyp_pathways || [];
45
+ const shared = [...new Set(allDrug.filter(c => compCyps.includes(c)))];
46
+ if (shared.length > 0) cypMech = `Shared CYP450 pathway(s): ${shared.join(", ")}. ${compound.name} may alter how ${drugName} is metabolized.`;
47
+ }
48
+ const parts = [`Interaction between ${compound.name} and ${drugName}:`, `Severity: ${severity}`];
49
+ if (totalFaers > 0) parts.push(`FDA Adverse Event Reports: ${totalFaers} serious report(s) in FAERS.`);
50
+ if (cypMech) parts.push(`Mechanism: ${cypMech}`);
51
+ const mechs = research.map(i => i.mechanism || i.description).filter(Boolean);
52
+ if (mechs.length > 0) parts.push(`Research: ${mechs.join(". ")}`);
53
+ const recs = [...new Set(di.map(i => i.recommendation).filter(Boolean))];
54
+ if (recs.length > 0) parts.push(`Recommendation: ${recs.join(". ")}`);
55
+ return { supplement: supplementName, drug: drugName, resolved_compound: compoundId, compound_name: compound.name, severity, explanation: parts.join("\n\n"), confidence: totalFaers > 10 ? "high" : totalFaers > 0 ? "medium" : "low", evidence_count: di.length, faers_report_count: totalFaers, has_cyp_conflict: cypMech !== "" };
56
+ }
57
+
58
+ async function buildEvidence(supplementName, drugName) {
59
+ const sr = await searchCompounds(supplementName, 1);
60
+ const compound = sr?.results?.[0];
61
+ if (!compound) return { supplement: supplementName, drug: drugName, evidence_items: [], error: `Could not resolve "${supplementName}".` };
62
+ const compoundId = compound.compound_id;
63
+ const interactions = await getCompoundInteractions(compoundId);
64
+ const di = (interactions?.interactions || []).filter(i => i.target_id?.toLowerCase().includes(drugName.toLowerCase()) || i.target_name?.toLowerCase().includes(drugName.toLowerCase()));
65
+ let drugProfile = null;
66
+ try { drugProfile = await getDrugProfile(drugName.toLowerCase().replace(/\s+/g, "_")); } catch(e) {}
67
+ const items = [];
68
+ for (const s of di.filter(i => i.source_origin === "OPENFDA")) {
69
+ items.push({ type: "FAERS_SIGNAL", source: "FDA FAERS", description: `${s.metadata?.report_count || 0} serious adverse event reports`, severity: s.severity, report_count: s.metadata?.report_count || 0, signal_score: s.combined_confidence, caveat: "FAERS reports are voluntary and do not prove causation." });
70
+ }
71
+ for (const f of di.filter(i => i.source_origin !== "OPENFDA")) {
72
+ items.push({ type: "RESEARCH_FINDING", source: f.source_origin || "Research", description: f.mechanism || f.description || "Interaction documented", severity: f.severity, evidence_grade: f.evidence_grade || "not_graded", recommendation: f.recommendation || null });
73
+ }
74
+ if (drugProfile?.profile?.cyp_pathways) {
75
+ const cyps = drugProfile.profile.cyp_pathways;
76
+ const cd = await getCompound(compoundId);
77
+ const compCyps = cd?.compound?.data?.cyp_pathways || [];
78
+ const allDrug = [...(cyps.metabolized_by||[]),...(cyps.inhibits||[]),...(cyps.induces||[])];
79
+ const shared = [...new Set(allDrug.filter(c => compCyps.includes(c)))];
80
+ if (shared.length > 0) items.push({ type: "CYP_PATHWAY_CONFLICT", source: "FDA drug label + compound data", shared_pathways: shared, clinical_significance: "Shared CYP pathways may alter drug metabolism." });
81
+ }
82
+ return { supplement: supplementName, drug: drugName, resolved_compound: compoundId, compound_name: compound.name, evidence_items: items, total_evidence_count: items.length, evidence_types: [...new Set(items.map(e => e.type))] };
83
+ }
84
+
85
+ const server = new Server({ name: "truthstack", version: "2.1.0" }, { capabilities: { tools: {} } });
86
+
87
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
88
+ tools: [
89
+ { name: "check_interactions", description: "Check if supplements are safe with medications. Returns risk level, FDA adverse event data, CYP450 conflicts. Use when user mentions supplements + meds.", inputSchema: { type: "object", properties: { supplements: { type: "array", items: { type: "string" }, description: "Supplement names (handles brands, abbreviations, misspellings)" }, medications: { type: "array", items: { type: "string" }, description: "Medication names (generic or brand)" } }, required: ["supplements", "medications"] } },
90
+ { name: "search_compounds", description: "Fuzzy search for supplement compounds. 584 aliases across 95 compounds. Resolves misspellings, brands, abbreviations.", inputSchema: { type: "object", properties: { query: { type: "string", description: "Search query" }, limit: { type: "number", description: "Max results (default 5)" } }, required: ["query"] } },
91
+ { name: "get_compound_info", description: "Get detailed compound profile with interactions, research findings, and aliases.", inputSchema: { type: "object", properties: { compound_id: { type: "string", description: "Compound ID from search_compounds" } }, required: ["compound_id"] } },
92
+ { name: "explain_interaction", description: "Human-readable explanation of WHY an interaction is risky. Returns mechanism, severity, evidence summary.", inputSchema: { type: "object", properties: { supplement: { type: "string", description: "Supplement name" }, drug: { type: "string", description: "Drug name" } }, required: ["supplement", "drug"] } },
93
+ { name: "get_evidence", description: "Raw evidence bundle: FAERS counts, CYP data, research grades, label warnings. For citing sources.", inputSchema: { type: "object", properties: { supplement: { type: "string", description: "Supplement name" }, drug: { type: "string", description: "Drug name" } }, required: ["supplement", "drug"] } },
94
+ { name: "get_safety_signals", description: "Get FDA adverse event safety signals (CAERS) for a supplement. Returns PRR analysis, signal strength, category alerts for hepatic/cardiac/bleeding/renal risks.", inputSchema: { type: "object", properties: { compound: { type: "string", description: "Supplement name (e.g. turmeric, kava, green_tea_extract)" } }, required: ["compound"] } },
95
+ ]
96
+ }));
97
+
98
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
99
+ const { name, arguments: args = {} } = request.params;
100
+ try {
101
+ let result;
102
+ switch (name) {
103
+ case "check_interactions":
104
+ if (!args.supplements || !args.medications) return { content: [{ type: "text", text: JSON.stringify({ error: "Provide 'supplements' (array) and 'medications' (array)", example: { supplements: ["ashwagandha"], medications: ["sertraline"] } }) }], isError: true };
105
+ result = await checkInteractions(args.supplements, args.medications);
106
+ break;
107
+ case "search_compounds":
108
+ if (!args.query) return { content: [{ type: "text", text: JSON.stringify({ error: "Provide 'query' string" }) }], isError: true };
109
+ result = await searchCompounds(args.query, args.limit || 5);
110
+ break;
111
+ case "get_compound_info":
112
+ if (!args.compound_id) return { content: [{ type: "text", text: JSON.stringify({ error: "Provide 'compound_id'" }) }], isError: true };
113
+ const [comp, ints] = await Promise.all([getCompound(args.compound_id), getCompoundInteractions(args.compound_id)]);
114
+ result = { ...comp, interactions: ints?.interactions || [] };
115
+ break;
116
+ case "explain_interaction":
117
+ if (!args.supplement || !args.drug) return { content: [{ type: "text", text: JSON.stringify({ error: "Provide 'supplement' and 'drug'" }) }], isError: true };
118
+ result = await buildExplanation(args.supplement, args.drug);
119
+ break;
120
+ case "get_evidence":
121
+ if (!args.supplement || !args.drug) return { content: [{ type: "text", text: JSON.stringify({ error: "Provide 'supplement' and 'drug'" }) }], isError: true };
122
+ result = await buildEvidence(args.supplement, args.drug);
123
+ break;
124
+ case "get_safety_signals":
125
+ if (!args.compound) return { content: [{ type: "text", text: JSON.stringify({ error: "Provide compound string" }) }], isError: true };
126
+ result = await vaultFetch("/api/safety/profile/" + encodeURIComponent(args.compound));
127
+ break;
128
+ default:
129
+ return { content: [{ type: "text", text: `Unknown tool: ${name}` }], isError: true };
130
+ }
131
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
132
+ } catch (error) {
133
+ return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
134
+ }
135
+ });
136
+
137
+ async function main() {
138
+ const transport = new StdioServerTransport();
139
+ await server.connect(transport);
140
+ console.error("TruthStack MCP Server v2 running (6 tools, stdio transport)");
141
+ }
142
+ main().catch(e => { console.error("Fatal:", e); process.exit(1); });