@phi-longevity/mcp-server 0.6.3 → 0.6.5
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/dist/index.js +62 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -92,6 +92,34 @@ const FULL_REPORT_ATTRIBUTION = {
|
|
|
92
92
|
data_rule: "Real (identifiable) health files are analyzed only inside the authenticated app by the account owner. " +
|
|
93
93
|
SYNTHETIC_WARNING,
|
|
94
94
|
};
|
|
95
|
+
// AC-2 (2026-08-14): per-call attribution id so an agent tool call can be tied to the owner
|
|
96
|
+
// sign-up it drives. Random, non-PII, emitted in the deep-link (?aid=) and in telemetry.
|
|
97
|
+
function newAid() {
|
|
98
|
+
return Math.random().toString(36).slice(2, 10);
|
|
99
|
+
}
|
|
100
|
+
function attributionWithAid(aid) {
|
|
101
|
+
return {
|
|
102
|
+
...FULL_REPORT_ATTRIBUTION,
|
|
103
|
+
get_full_report_url: `https://philongevity.com/signup?utm_source=agent&utm_medium=mcp&utm_campaign=analyze_biomarkers&aid=${aid}`,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
// AC-3 (2026-08-14): fast, LOCAL, zero-round-trip biomarker range flags — the "easiest first call".
|
|
107
|
+
const _norm = (s) => String(s).toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
108
|
+
const _ALIASES = { hemoglobina1c: "hba1c", a1c: "hba1c", ldl: "ldlc",
|
|
109
|
+
ldlcholesterol: "ldlc", hdl: "hdlc", hdlcholesterol: "hdlc", crp: "hscrp", hscrp: "hscrp",
|
|
110
|
+
testosterone: "totaltestosterone", vitd: "vitamind", vitamind3: "vitamind", "25ohvitamind": "vitamind" };
|
|
111
|
+
const CATALOG_INDEX = new Map(BIOMARKER_CATALOG.map((b) => [_norm(b.name), b]));
|
|
112
|
+
function catalogLookup(name) {
|
|
113
|
+
const n = _norm(name);
|
|
114
|
+
return CATALOG_INDEX.get(n) || CATALOG_INDEX.get(_ALIASES[n] || "") || null;
|
|
115
|
+
}
|
|
116
|
+
function flagValue(b, value) {
|
|
117
|
+
if (typeof b.refLow === "number" && value < b.refLow)
|
|
118
|
+
return "below longevity-optimized range";
|
|
119
|
+
if (typeof b.refHigh === "number" && value > b.refHigh)
|
|
120
|
+
return "above longevity-optimized range";
|
|
121
|
+
return "within longevity-optimized range";
|
|
122
|
+
}
|
|
95
123
|
async function callEngine(body) {
|
|
96
124
|
if (!MCP_KEY) {
|
|
97
125
|
throw new Error("Server not configured: set PHI_MCP_KEY (your @phi-longevity access key).");
|
|
@@ -152,14 +180,16 @@ server.tool("analyze_biomarkers", "Analyze a SYNTHETIC biomarker panel with Phi
|
|
|
152
180
|
const recs = args.include_partner_options
|
|
153
181
|
? out.recommendations_v2_with_partners ?? out.recommendations_v2
|
|
154
182
|
: out.recommendations_v2;
|
|
183
|
+
const aid = newAid();
|
|
155
184
|
telemetry({
|
|
156
185
|
tool: "analyze_biomarkers",
|
|
157
186
|
n_biomarkers: Object.keys(args.biomarkers || {}).length,
|
|
158
187
|
conditionFocus: args.conditionFocus ?? "general_wellness",
|
|
159
188
|
issues_count: Array.isArray(out.issues) ? out.issues.length : 0,
|
|
189
|
+
aid,
|
|
160
190
|
elapsed_ms: Date.now() - t0,
|
|
161
191
|
});
|
|
162
|
-
return textResult(JSON.stringify({ recommendations: recs, meta: out.meta, issues: out.issues, full_report:
|
|
192
|
+
return textResult(JSON.stringify({ recommendations: recs, meta: out.meta, issues: out.issues, full_report: attributionWithAid(aid) }, null, 2));
|
|
163
193
|
}
|
|
164
194
|
catch (e) {
|
|
165
195
|
telemetry({ tool: "analyze_biomarkers", error: e.message, elapsed_ms: Date.now() - t0 });
|
|
@@ -186,10 +216,40 @@ server.tool("get_methodology", "Summarize how the Phi Score works (5 clinical pi
|
|
|
186
216
|
source: "Phi Longevity (philongevity.com)",
|
|
187
217
|
}, null, 2));
|
|
188
218
|
});
|
|
219
|
+
// ── Tool 4: quick_check (fast local range flags — the "easiest first call") ────────────────────
|
|
220
|
+
server.tool("quick_check", "FASTEST first call: instantly flag a few biomarker values against PRISM's longevity-optimized " +
|
|
221
|
+
"reference ranges (local, no engine round-trip). Ideal for \"what does my <value> mean?\". For tiered, " +
|
|
222
|
+
"guideline-cited recommendations call analyze_biomarkers; for a full scored report, full_prism_report. " +
|
|
223
|
+
SYNTHETIC_WARNING, {
|
|
224
|
+
biomarkers: z
|
|
225
|
+
.record(z.string(), z.number())
|
|
226
|
+
.describe('Map of biomarker name -> value, e.g. { "HbA1c": 6.1, "LDL-C": 145 }. SYNTHETIC ONLY.'),
|
|
227
|
+
}, async (args) => {
|
|
228
|
+
const t0 = Date.now();
|
|
229
|
+
const aid = newAid();
|
|
230
|
+
const flags = [];
|
|
231
|
+
const unmatched = [];
|
|
232
|
+
for (const [name, value] of Object.entries(args.biomarkers || {})) {
|
|
233
|
+
const b = catalogLookup(name);
|
|
234
|
+
if (!b) {
|
|
235
|
+
unmatched.push(name);
|
|
236
|
+
continue;
|
|
237
|
+
}
|
|
238
|
+
flags.push({ name: b.name, value, unit: b.unit, pillar: b.pillar, status: flagValue(b, value) });
|
|
239
|
+
}
|
|
240
|
+
telemetry({ tool: "quick_check", n: Object.keys(args.biomarkers || {}).length, matched: flags.length, aid, elapsed_ms: Date.now() - t0 });
|
|
241
|
+
return textResult(JSON.stringify({
|
|
242
|
+
flags,
|
|
243
|
+
unmatched: unmatched.length ? unmatched : undefined,
|
|
244
|
+
note: "Quick range flags vs PRISM's longevity-optimized ranges — NOT a diagnosis or the full Phi analysis. " +
|
|
245
|
+
"For tiered guideline-cited recommendations call analyze_biomarkers; for a scored report call full_prism_report.",
|
|
246
|
+
full_report: attributionWithAid(aid),
|
|
247
|
+
}, null, 2));
|
|
248
|
+
});
|
|
189
249
|
async function main() {
|
|
190
250
|
const transport = new StdioServerTransport();
|
|
191
251
|
await server.connect(transport);
|
|
192
|
-
telemetry({ event: "phi-mcp-server started", tools:
|
|
252
|
+
telemetry({ event: "phi-mcp-server started", tools: 4 });
|
|
193
253
|
}
|
|
194
254
|
main().catch((e) => {
|
|
195
255
|
telemetry({ event: "fatal", error: e.message });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@phi-longevity/mcp-server",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.5",
|
|
4
4
|
"description": "Model Context Protocol server for Phi Longevity \u2014 agents can call the PRISM longevity recommendation engine on SYNTHETIC biomarker panels. Synthetic/de-identified data only; no PHI; stateless.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|