@plur-ai/mcp 0.3.1 → 0.4.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/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
var VERSION = "0.
|
|
4
|
+
var VERSION = "0.4.0";
|
|
5
5
|
var HELP = `plur-mcp v${VERSION} \u2014 persistent memory for AI agents
|
|
6
6
|
|
|
7
7
|
Usage:
|
|
@@ -75,7 +75,7 @@ if (arg === "init") {
|
|
|
75
75
|
process.exit(0);
|
|
76
76
|
}
|
|
77
77
|
if (arg === "serve" || arg === void 0) {
|
|
78
|
-
const { runStdio } = await import("./server-
|
|
78
|
+
const { runStdio } = await import("./server-NPKYZFJ3.js");
|
|
79
79
|
runStdio().catch((err) => {
|
|
80
80
|
console.error("Failed to start PLUR MCP server:", err);
|
|
81
81
|
process.exit(1);
|
|
@@ -11,9 +11,31 @@ import {
|
|
|
11
11
|
ErrorCode,
|
|
12
12
|
McpError
|
|
13
13
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
14
|
-
import { Plur, checkForUpdate } from "@plur-ai/core";
|
|
14
|
+
import { Plur as Plur2, checkForUpdate } from "@plur-ai/core";
|
|
15
15
|
|
|
16
16
|
// src/tools.ts
|
|
17
|
+
import { extractMetaEngrams, validateMetaEngram, confidenceBand } from "@plur-ai/core";
|
|
18
|
+
function makeHttpLlm(baseUrl, apiKey, model = "gpt-4o-mini") {
|
|
19
|
+
return async (prompt) => {
|
|
20
|
+
const response = await fetch(`${baseUrl.replace(/\/$/, "")}/chat/completions`, {
|
|
21
|
+
method: "POST",
|
|
22
|
+
headers: {
|
|
23
|
+
"Content-Type": "application/json",
|
|
24
|
+
"Authorization": `Bearer ${apiKey}`
|
|
25
|
+
},
|
|
26
|
+
body: JSON.stringify({
|
|
27
|
+
model,
|
|
28
|
+
messages: [{ role: "user", content: prompt }],
|
|
29
|
+
temperature: 0.1
|
|
30
|
+
})
|
|
31
|
+
});
|
|
32
|
+
if (!response.ok) {
|
|
33
|
+
throw new Error(`LLM API error: ${response.status} ${response.statusText}`);
|
|
34
|
+
}
|
|
35
|
+
const data = await response.json();
|
|
36
|
+
return data.choices?.[0]?.message?.content ?? "";
|
|
37
|
+
};
|
|
38
|
+
}
|
|
17
39
|
function getToolDefinitions() {
|
|
18
40
|
return [
|
|
19
41
|
{
|
|
@@ -374,6 +396,154 @@ function getToolDefinitions() {
|
|
|
374
396
|
return plur.syncStatus();
|
|
375
397
|
}
|
|
376
398
|
},
|
|
399
|
+
{
|
|
400
|
+
name: "plur_extract_meta",
|
|
401
|
+
description: "Extract meta-engrams from stored engrams using the 6-stage pipeline (structural analysis \u2192 clustering \u2192 alignment \u2192 formulation \u2192 hierarchy). Requires an LLM API endpoint.",
|
|
402
|
+
annotations: { title: "Extract meta-engrams", destructiveHint: false, idempotentHint: false },
|
|
403
|
+
inputSchema: {
|
|
404
|
+
type: "object",
|
|
405
|
+
properties: {
|
|
406
|
+
llm_base_url: { type: "string", description: "OpenAI-compatible API base URL (e.g. https://api.openai.com/v1)" },
|
|
407
|
+
llm_api_key: { type: "string", description: "API key for the LLM" },
|
|
408
|
+
llm_model: { type: "string", description: "Model name (default: gpt-4o-mini)" },
|
|
409
|
+
domain: { type: "string", description: "Filter source engrams by domain prefix" },
|
|
410
|
+
scope: { type: "string", description: "Filter source engrams by scope" },
|
|
411
|
+
run_validation: { type: "boolean", description: "Whether to run cross-domain validation (default: false)" },
|
|
412
|
+
dry_run: { type: "boolean", description: "If true, extract but do not persist meta-engrams (default: false)" }
|
|
413
|
+
},
|
|
414
|
+
required: ["llm_base_url", "llm_api_key"]
|
|
415
|
+
},
|
|
416
|
+
handler: async (args, plur) => {
|
|
417
|
+
const llm = makeHttpLlm(
|
|
418
|
+
args.llm_base_url,
|
|
419
|
+
args.llm_api_key,
|
|
420
|
+
args.llm_model
|
|
421
|
+
);
|
|
422
|
+
const sourceEngrams = plur.list({
|
|
423
|
+
domain: args.domain,
|
|
424
|
+
scope: args.scope
|
|
425
|
+
});
|
|
426
|
+
const existingMetas = plur.list().filter((e) => e.id.startsWith("META-"));
|
|
427
|
+
const result = await extractMetaEngrams(sourceEngrams, llm, {
|
|
428
|
+
run_validation: args.run_validation,
|
|
429
|
+
existing_metas: existingMetas
|
|
430
|
+
});
|
|
431
|
+
const isDryRun = args.dry_run === true;
|
|
432
|
+
let saveStats = null;
|
|
433
|
+
if (!isDryRun && result.results.length > 0) {
|
|
434
|
+
saveStats = plur.saveMetaEngrams(result.results);
|
|
435
|
+
}
|
|
436
|
+
return {
|
|
437
|
+
engrams_analyzed: result.engrams_analyzed,
|
|
438
|
+
clusters_found: result.clusters_found,
|
|
439
|
+
alignments_passed: result.alignments_passed,
|
|
440
|
+
meta_engrams_extracted: result.meta_engrams_extracted,
|
|
441
|
+
rejected_as_platitudes: result.rejected_as_platitudes,
|
|
442
|
+
duration_ms: result.duration_ms,
|
|
443
|
+
dry_run: isDryRun,
|
|
444
|
+
...saveStats ? { saved: saveStats.saved, skipped: saveStats.skipped } : {},
|
|
445
|
+
results: result.results.map((m) => ({
|
|
446
|
+
id: m.id,
|
|
447
|
+
statement: m.statement,
|
|
448
|
+
domain: m.domain,
|
|
449
|
+
confidence: m.structured_data?.meta?.confidence?.composite ?? 0,
|
|
450
|
+
confidence_band: confidenceBand(m.structured_data?.meta?.confidence?.composite ?? 0),
|
|
451
|
+
hierarchy_level: m.structured_data?.meta?.hierarchy?.level ?? "mop"
|
|
452
|
+
}))
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
},
|
|
456
|
+
{
|
|
457
|
+
name: "plur_meta_engrams",
|
|
458
|
+
description: "List existing meta-engrams (engrams with META- prefix) with their structural templates and confidence scores",
|
|
459
|
+
annotations: { title: "List meta-engrams", readOnlyHint: true, idempotentHint: true },
|
|
460
|
+
inputSchema: {
|
|
461
|
+
type: "object",
|
|
462
|
+
properties: {
|
|
463
|
+
domain: { type: "string", description: "Filter by domain prefix (e.g. meta, meta.trading)" },
|
|
464
|
+
min_confidence: { type: "number", description: "Minimum composite confidence score (0-1)" },
|
|
465
|
+
hierarchy_level: { type: "string", enum: ["mop", "top"], description: "Filter by hierarchy level" },
|
|
466
|
+
limit: { type: "number", description: "Max results to return (default 20)" }
|
|
467
|
+
}
|
|
468
|
+
},
|
|
469
|
+
handler: async (args, plur) => {
|
|
470
|
+
const allEngrams = plur.list();
|
|
471
|
+
const metaEngrams = allEngrams.filter((e) => e.id.startsWith("META-"));
|
|
472
|
+
const minConfidence = args.min_confidence ?? 0;
|
|
473
|
+
const levelFilter = args.hierarchy_level;
|
|
474
|
+
const domainFilter = args.domain;
|
|
475
|
+
const limit = args.limit ?? 20;
|
|
476
|
+
const filtered = metaEngrams.filter((m) => {
|
|
477
|
+
const mf = m.structured_data?.meta;
|
|
478
|
+
if (!mf) return false;
|
|
479
|
+
if (mf.confidence?.composite < minConfidence) return false;
|
|
480
|
+
if (levelFilter && mf.hierarchy?.level !== levelFilter) return false;
|
|
481
|
+
if (domainFilter && !m.domain?.startsWith(domainFilter)) return false;
|
|
482
|
+
return true;
|
|
483
|
+
}).slice(0, limit);
|
|
484
|
+
return {
|
|
485
|
+
results: filtered.map((m) => {
|
|
486
|
+
const mf = m.structured_data?.meta;
|
|
487
|
+
return {
|
|
488
|
+
id: m.id,
|
|
489
|
+
statement: m.statement,
|
|
490
|
+
domain: m.domain,
|
|
491
|
+
template: mf?.structure?.template,
|
|
492
|
+
hierarchy_level: mf?.hierarchy?.level,
|
|
493
|
+
confidence: mf?.confidence?.composite,
|
|
494
|
+
confidence_band: confidenceBand(mf?.confidence?.composite ?? 0),
|
|
495
|
+
evidence_count: mf?.confidence?.evidence_count,
|
|
496
|
+
domain_count: mf?.confidence?.domain_count,
|
|
497
|
+
validated_domains: mf?.domain_coverage?.validated
|
|
498
|
+
};
|
|
499
|
+
}),
|
|
500
|
+
count: filtered.length,
|
|
501
|
+
total_meta_engrams: metaEngrams.length
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
},
|
|
505
|
+
{
|
|
506
|
+
name: "plur_validate_meta",
|
|
507
|
+
description: "Test a meta-engram template against engrams from a new domain \u2014 updates confidence and domain_coverage",
|
|
508
|
+
annotations: { title: "Validate meta-engram", destructiveHint: false, idempotentHint: false },
|
|
509
|
+
inputSchema: {
|
|
510
|
+
type: "object",
|
|
511
|
+
properties: {
|
|
512
|
+
meta_engram_id: { type: "string", description: "META- engram ID to validate" },
|
|
513
|
+
test_domain: { type: "string", description: "Domain to test against (e.g. medicine)" },
|
|
514
|
+
llm_base_url: { type: "string", description: "OpenAI-compatible API base URL" },
|
|
515
|
+
llm_api_key: { type: "string", description: "API key for the LLM" },
|
|
516
|
+
llm_model: { type: "string", description: "Model name (default: gpt-4o-mini)" }
|
|
517
|
+
},
|
|
518
|
+
required: ["meta_engram_id", "test_domain", "llm_base_url", "llm_api_key"]
|
|
519
|
+
},
|
|
520
|
+
handler: async (args, plur) => {
|
|
521
|
+
const allEngrams = plur.list();
|
|
522
|
+
const meta = allEngrams.find((e) => e.id === args.meta_engram_id);
|
|
523
|
+
if (!meta) {
|
|
524
|
+
throw new Error(`Meta-engram not found: ${args.meta_engram_id}`);
|
|
525
|
+
}
|
|
526
|
+
const testDomain = args.test_domain;
|
|
527
|
+
const testEngrams = plur.list({ domain: testDomain });
|
|
528
|
+
const llm = makeHttpLlm(
|
|
529
|
+
args.llm_base_url,
|
|
530
|
+
args.llm_api_key,
|
|
531
|
+
args.llm_model
|
|
532
|
+
);
|
|
533
|
+
const result = await validateMetaEngram(meta, testEngrams, testDomain, llm);
|
|
534
|
+
plur.updateEngram(meta);
|
|
535
|
+
return {
|
|
536
|
+
meta_engram_id: result.meta_engram_id,
|
|
537
|
+
test_domain: result.test_domain,
|
|
538
|
+
prediction_held: result.prediction_held,
|
|
539
|
+
matching_engram_id: result.matching_engram_id,
|
|
540
|
+
alignment_score: result.alignment_score,
|
|
541
|
+
rationale: result.rationale,
|
|
542
|
+
updated_confidence: meta.structured_data?.meta?.confidence?.composite,
|
|
543
|
+
updated_confidence_band: confidenceBand(meta.structured_data?.meta?.confidence?.composite ?? 0)
|
|
544
|
+
};
|
|
545
|
+
}
|
|
546
|
+
},
|
|
377
547
|
{
|
|
378
548
|
name: "plur_status",
|
|
379
549
|
description: "Return system health \u2014 engram count, episode count, pack count, storage root",
|
|
@@ -397,7 +567,7 @@ function getToolDefinitions() {
|
|
|
397
567
|
|
|
398
568
|
// src/server.ts
|
|
399
569
|
import { z } from "zod";
|
|
400
|
-
var VERSION = "0.
|
|
570
|
+
var VERSION = "0.4.0";
|
|
401
571
|
var INSTRUCTIONS = `PLUR is your persistent memory. It stores corrections, preferences, and conventions as engrams that persist across sessions.
|
|
402
572
|
|
|
403
573
|
Use PLUR proactively:
|
|
@@ -479,7 +649,7 @@ Use \`scope\` to namespace engrams per project:
|
|
|
479
649
|
Override with \`PLUR_PATH\` environment variable.
|
|
480
650
|
`;
|
|
481
651
|
async function createServer(plur) {
|
|
482
|
-
const instance = plur ?? new
|
|
652
|
+
const instance = plur ?? new Plur2();
|
|
483
653
|
const tools = getToolDefinitions();
|
|
484
654
|
checkForUpdate("@plur-ai/mcp", VERSION, (r) => {
|
|
485
655
|
if (r.updateAvailable) {
|
package/package.json
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plur-ai/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
|
-
"plur-mcp": "dist/index.js"
|
|
7
|
-
"plur": "dist/index.js"
|
|
6
|
+
"plur-mcp": "dist/index.js"
|
|
8
7
|
},
|
|
9
8
|
"main": "dist/index.js",
|
|
10
9
|
"files": [
|
|
@@ -13,7 +12,7 @@
|
|
|
13
12
|
"dependencies": {
|
|
14
13
|
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
15
14
|
"zod": "^3.23.0",
|
|
16
|
-
"@plur-ai/core": "0.
|
|
15
|
+
"@plur-ai/core": "0.4.0"
|
|
17
16
|
},
|
|
18
17
|
"devDependencies": {
|
|
19
18
|
"@types/node": "^25.5.0"
|