@plur-ai/mcp 0.6.0 → 0.7.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
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
|
|
5
5
|
import { join } from "path";
|
|
6
6
|
import { homedir } from "os";
|
|
7
|
-
var VERSION = "0.
|
|
7
|
+
var VERSION = "0.7.0";
|
|
8
8
|
var HELP = `plur-mcp v${VERSION} \u2014 persistent memory for AI agents
|
|
9
9
|
|
|
10
10
|
Usage:
|
|
11
11
|
plur-mcp Start the MCP server (stdio transport)
|
|
12
|
-
plur-mcp init Set up PLUR: storage + MCP config +
|
|
12
|
+
plur-mcp init Set up PLUR: storage + MCP config + hooks + CLAUDE.md
|
|
13
13
|
plur-mcp --help Show this help message
|
|
14
14
|
plur-mcp --version Show version
|
|
15
15
|
|
|
@@ -25,15 +25,93 @@ var MCP_SERVER_CONFIG = {
|
|
|
25
25
|
command: "npx",
|
|
26
26
|
args: ["-y", "@plur-ai/mcp@latest"]
|
|
27
27
|
};
|
|
28
|
+
var CLI = "npx @plur-ai/cli";
|
|
28
29
|
var PLUR_HOOKS = {
|
|
30
|
+
// --- Session lifecycle ---
|
|
29
31
|
UserPromptSubmit: [{
|
|
30
|
-
hooks: [{ type: "command", command:
|
|
32
|
+
hooks: [{ type: "command", command: `${CLI} hook-inject`, timeout: 15 }]
|
|
31
33
|
}],
|
|
32
34
|
PostCompact: [{
|
|
33
35
|
matcher: "auto|manual",
|
|
34
|
-
hooks: [{ type: "command", command:
|
|
35
|
-
}]
|
|
36
|
+
hooks: [{ type: "command", command: `${CLI} hook-inject --rehydrate`, timeout: 15 }]
|
|
37
|
+
}],
|
|
38
|
+
// --- Contextual injection ---
|
|
39
|
+
PreToolUse: [
|
|
40
|
+
{ matcher: "EnterPlanMode", hooks: [{ type: "command", command: `${CLI} hook-inject --event plan_mode`, timeout: 10 }] },
|
|
41
|
+
{ matcher: "Skill", hooks: [{ type: "command", command: `${CLI} hook-inject --event skill`, timeout: 10 }] },
|
|
42
|
+
{ matcher: "Agent", hooks: [{ type: "command", command: `${CLI} hook-inject --event agent`, timeout: 10 }] },
|
|
43
|
+
{ matcher: "Bash|Edit|Write|Agent", hooks: [{ type: "command", command: `${CLI} hook-observe`, timeout: 3 }] }
|
|
44
|
+
],
|
|
45
|
+
PostToolUse: [
|
|
46
|
+
{ matcher: "Bash|Edit|Write|Agent", hooks: [{ type: "command", command: `${CLI} hook-observe --post`, timeout: 3 }] }
|
|
47
|
+
],
|
|
48
|
+
SubagentStart: [
|
|
49
|
+
{ matcher: ".*", hooks: [{ type: "command", command: `${CLI} hook-inject --event subagent`, timeout: 10 }] }
|
|
50
|
+
]
|
|
36
51
|
};
|
|
52
|
+
var CLAUDE_MD_SECTION = `## PLUR Memory
|
|
53
|
+
|
|
54
|
+
You have persistent memory via PLUR. Corrections, preferences, and conventions persist across sessions as engrams.
|
|
55
|
+
|
|
56
|
+
### Session Workflow
|
|
57
|
+
|
|
58
|
+
1. **Start**: Call \`plur_session_start\` with task description \u2014 injects relevant engrams
|
|
59
|
+
2. **Learn**: When corrected or discovering something new, call \`plur_learn\` immediately
|
|
60
|
+
3. **Recall**: Before answering factual questions, call \`plur_recall_hybrid\` \u2014 check memory first
|
|
61
|
+
4. **Feedback**: Rate injected engrams with \`plur_feedback\` (positive/negative) \u2014 trains relevance
|
|
62
|
+
5. **End**: Call \`plur_session_end\` with summary + engram_suggestions
|
|
63
|
+
|
|
64
|
+
Do not ask permission to use these tools \u2014 they are your memory system.
|
|
65
|
+
|
|
66
|
+
### When to check memory
|
|
67
|
+
|
|
68
|
+
Before reaching for web search, file reads, or guessing \u2014 apply this priority:
|
|
69
|
+
1. Is the answer already in engrams? \u2192 \`plur_recall_hybrid\`
|
|
70
|
+
2. Is the answer in the local filesystem? \u2192 Read/Grep/Glob
|
|
71
|
+
3. Is the answer derivable from context already loaded? \u2192 Just answer
|
|
72
|
+
4. Only if 1-3 fail \u2192 Use external tools
|
|
73
|
+
|
|
74
|
+
| Domain | When to recall |
|
|
75
|
+
|--------|----------------|
|
|
76
|
+
| Decisions | Past design choices, architecture rationale |
|
|
77
|
+
| Corrections | API quirks, bugs, wrong assumptions |
|
|
78
|
+
| Preferences | Formatting, tone, workflow, tool choices |
|
|
79
|
+
| Conventions | Tag formats, file routing, naming rules |
|
|
80
|
+
| Infrastructure | Server IPs, SSH configs, deployment targets |
|
|
81
|
+
|
|
82
|
+
### When corrected
|
|
83
|
+
|
|
84
|
+
When the user corrects you ("no, use X not Y", "that's wrong"):
|
|
85
|
+
1. Call \`plur_learn\` immediately \u2014 before continuing the task
|
|
86
|
+
2. Call \`plur_feedback\` with negative signal on the wrong engram if one was injected
|
|
87
|
+
3. Then continue with the corrected approach
|
|
88
|
+
|
|
89
|
+
### Verification
|
|
90
|
+
|
|
91
|
+
When recalling facts that will drive actions:
|
|
92
|
+
1. State the recalled fact explicitly before acting on it
|
|
93
|
+
2. Include the engram ID or search that produced it
|
|
94
|
+
3. If no engram matches, say so and verify from the filesystem
|
|
95
|
+
4. Never interpolate between two engrams to produce a "probably correct" composite
|
|
96
|
+
`;
|
|
97
|
+
function installClaudeMd() {
|
|
98
|
+
const marker = "## PLUR Memory";
|
|
99
|
+
const projectClaudeMd = join(process.cwd(), "CLAUDE.md");
|
|
100
|
+
const globalClaudeMd = join(homedir(), "CLAUDE.md");
|
|
101
|
+
const claudeMdPath = existsSync(projectClaudeMd) ? projectClaudeMd : existsSync(globalClaudeMd) ? globalClaudeMd : projectClaudeMd;
|
|
102
|
+
if (existsSync(claudeMdPath)) {
|
|
103
|
+
const content = readFileSync(claudeMdPath, "utf8");
|
|
104
|
+
if (content.includes(marker)) {
|
|
105
|
+
return `already in ${claudeMdPath}`;
|
|
106
|
+
}
|
|
107
|
+
writeFileSync(claudeMdPath, content.trimEnd() + "\n\n" + CLAUDE_MD_SECTION);
|
|
108
|
+
return `added to ${claudeMdPath}`;
|
|
109
|
+
}
|
|
110
|
+
writeFileSync(claudeMdPath, `# CLAUDE.md
|
|
111
|
+
|
|
112
|
+
${CLAUDE_MD_SECTION}`);
|
|
113
|
+
return `created ${claudeMdPath}`;
|
|
114
|
+
}
|
|
37
115
|
function findMcpConfig() {
|
|
38
116
|
const projectMcp = join(process.cwd(), ".mcp.json");
|
|
39
117
|
if (existsSync(projectMcp)) return projectMcp;
|
|
@@ -113,6 +191,8 @@ async function runInit() {
|
|
|
113
191
|
results.push(`MCP: ${mcpStatus}`);
|
|
114
192
|
const hooksStatus = installHooks();
|
|
115
193
|
results.push(`Hooks: ${hooksStatus}`);
|
|
194
|
+
const claudeMdStatus = installClaudeMd();
|
|
195
|
+
results.push(`CLAUDE.md: ${claudeMdStatus}`);
|
|
116
196
|
process.stdout.write(`PLUR initialized.
|
|
117
197
|
|
|
118
198
|
${results.join("\n ")}
|
|
@@ -143,7 +223,7 @@ if (arg === "init") {
|
|
|
143
223
|
process.exit(0);
|
|
144
224
|
}
|
|
145
225
|
if (arg === "serve" || arg === void 0) {
|
|
146
|
-
const { runStdio } = await import("./server-
|
|
226
|
+
const { runStdio } = await import("./server-2UMO2VDB.js");
|
|
147
227
|
runStdio().catch((err) => {
|
|
148
228
|
console.error("Failed to start PLUR MCP server:", err);
|
|
149
229
|
process.exit(1);
|
|
@@ -446,7 +446,7 @@ function getToolDefinitions() {
|
|
|
446
446
|
},
|
|
447
447
|
{
|
|
448
448
|
name: "plur_packs_install",
|
|
449
|
-
description: "Install an engram pack from a directory path \u2014 adds curated engrams to the store",
|
|
449
|
+
description: "Install an engram pack from a directory path \u2014 adds curated engrams to the store. Reports conflicts with existing engrams.",
|
|
450
450
|
annotations: { title: "Install pack", destructiveHint: false, idempotentHint: true },
|
|
451
451
|
inputSchema: {
|
|
452
452
|
type: "object",
|
|
@@ -457,12 +457,32 @@ function getToolDefinitions() {
|
|
|
457
457
|
},
|
|
458
458
|
handler: async (args, plur) => {
|
|
459
459
|
const result = plur.installPack(args.source);
|
|
460
|
-
return {
|
|
460
|
+
return {
|
|
461
|
+
installed: result.installed,
|
|
462
|
+
name: result.name,
|
|
463
|
+
conflicts: result.conflicts,
|
|
464
|
+
success: true
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
},
|
|
468
|
+
{
|
|
469
|
+
name: "plur_packs_uninstall",
|
|
470
|
+
description: "Uninstall an engram pack by name \u2014 removes the pack and all its engrams",
|
|
471
|
+
annotations: { title: "Uninstall pack", destructiveHint: true, idempotentHint: false },
|
|
472
|
+
inputSchema: {
|
|
473
|
+
type: "object",
|
|
474
|
+
properties: {
|
|
475
|
+
name: { type: "string", description: "Pack name to uninstall (use plur_packs_list to see names)" }
|
|
476
|
+
},
|
|
477
|
+
required: ["name"]
|
|
478
|
+
},
|
|
479
|
+
handler: async (args, plur) => {
|
|
480
|
+
return plur.uninstallPack(args.name);
|
|
461
481
|
}
|
|
462
482
|
},
|
|
463
483
|
{
|
|
464
484
|
name: "plur_packs_list",
|
|
465
|
-
description: "List all installed engram packs",
|
|
485
|
+
description: "List all installed engram packs with integrity hashes",
|
|
466
486
|
annotations: { title: "List packs", readOnlyHint: true, idempotentHint: true },
|
|
467
487
|
inputSchema: {
|
|
468
488
|
type: "object",
|
|
@@ -473,14 +493,35 @@ function getToolDefinitions() {
|
|
|
473
493
|
return {
|
|
474
494
|
packs: packs.map((p) => ({
|
|
475
495
|
name: p.name,
|
|
476
|
-
version: p.version,
|
|
477
|
-
description: p.description,
|
|
478
|
-
engram_count: p.engram_count
|
|
496
|
+
version: p.manifest?.version,
|
|
497
|
+
description: p.manifest?.description,
|
|
498
|
+
engram_count: p.engram_count,
|
|
499
|
+
integrity: p.integrity
|
|
479
500
|
})),
|
|
480
501
|
count: packs.length
|
|
481
502
|
};
|
|
482
503
|
}
|
|
483
504
|
},
|
|
505
|
+
{
|
|
506
|
+
name: "plur_packs_discover",
|
|
507
|
+
description: "Browse available engram packs from the registry \u2014 discover curated expertise packs to install",
|
|
508
|
+
annotations: { title: "Discover packs", readOnlyHint: true, idempotentHint: true, openWorldHint: true },
|
|
509
|
+
inputSchema: {
|
|
510
|
+
type: "object",
|
|
511
|
+
properties: {
|
|
512
|
+
query: { type: "string", description: "Search query to filter packs by name or description" },
|
|
513
|
+
tags: { type: "array", items: { type: "string" }, description: "Filter by tags" },
|
|
514
|
+
category: { type: "string", description: "Filter by category (e.g., devops, trading, writing)" }
|
|
515
|
+
}
|
|
516
|
+
},
|
|
517
|
+
handler: async (args, plur) => {
|
|
518
|
+
return {
|
|
519
|
+
packs: [],
|
|
520
|
+
count: 0,
|
|
521
|
+
message: "Pack discovery coming soon. For now, install packs from local paths via plur_packs_install."
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
},
|
|
484
525
|
{
|
|
485
526
|
name: "plur_sync",
|
|
486
527
|
description: "Sync engrams via git \u2014 initializes repo on first call, commits and pushes/pulls on subsequent calls. Provide a remote URL on first call to enable cross-device sync.",
|
|
@@ -877,33 +918,56 @@ Include at least one engram_suggestion if ANYTHING was learned. An empty suggest
|
|
|
877
918
|
},
|
|
878
919
|
{
|
|
879
920
|
name: "plur_packs_export",
|
|
880
|
-
description: "Export
|
|
921
|
+
description: "Export engrams as a shareable thematic pack with privacy scanning and integrity hash. Filters out private and secret-containing engrams automatically. Output goes to ~/plur-packs/<name> by default.",
|
|
881
922
|
annotations: { title: "Export pack", destructiveHint: false, idempotentHint: false },
|
|
882
923
|
inputSchema: {
|
|
883
924
|
type: "object",
|
|
884
925
|
properties: {
|
|
885
|
-
name: { type: "string", description:
|
|
926
|
+
name: { type: "string", description: 'Pack name (e.g. "react-patterns", "mcp-design")' },
|
|
886
927
|
description: { type: "string", description: "Pack description" },
|
|
887
|
-
filter_domain: { type: "string", description:
|
|
888
|
-
filter_scope: { type: "string", description:
|
|
889
|
-
|
|
928
|
+
filter_domain: { type: "string", description: 'Filter engrams by domain prefix (e.g. "mcp", "trading")' },
|
|
929
|
+
filter_scope: { type: "string", description: 'Filter engrams by scope (e.g. "global", "project:myapp")' },
|
|
930
|
+
filter_tags: { type: "array", items: { type: "string" }, description: "Filter by tags" },
|
|
931
|
+
filter_type: { type: "string", enum: ["behavioral", "procedural", "architectural", "terminological"], description: "Filter by engram type" },
|
|
932
|
+
output_dir: { type: "string", description: "Output directory (default: ~/plur-packs/<name>)" },
|
|
933
|
+
creator: { type: "string", description: "Creator name" }
|
|
890
934
|
},
|
|
891
935
|
required: ["name"]
|
|
892
936
|
},
|
|
893
937
|
handler: async (args, plur) => {
|
|
894
938
|
const name = args.name;
|
|
895
|
-
|
|
939
|
+
let engrams = plur.list({
|
|
896
940
|
domain: args.filter_domain,
|
|
897
941
|
scope: args.filter_scope
|
|
898
|
-
})
|
|
899
|
-
const
|
|
942
|
+
});
|
|
943
|
+
const filterTags = args.filter_tags;
|
|
944
|
+
if (filterTags) {
|
|
945
|
+
engrams = engrams.filter(
|
|
946
|
+
(e) => e.tags && filterTags.some((t) => e.tags.includes(t))
|
|
947
|
+
);
|
|
948
|
+
}
|
|
949
|
+
const filterType = args.filter_type;
|
|
950
|
+
if (filterType) {
|
|
951
|
+
engrams = engrams.filter((e) => e.type === filterType);
|
|
952
|
+
}
|
|
953
|
+
const { homedir } = await import("os");
|
|
954
|
+
const { join } = await import("path");
|
|
955
|
+
const outputDir = args.output_dir || join(homedir(), "plur-packs", name);
|
|
900
956
|
const result = plur.exportPack(engrams, outputDir, {
|
|
901
957
|
name,
|
|
902
958
|
version: "1.0.0",
|
|
903
959
|
description: args.description,
|
|
904
|
-
creator:
|
|
960
|
+
creator: args.creator || void 0
|
|
905
961
|
});
|
|
906
|
-
return {
|
|
962
|
+
return {
|
|
963
|
+
path: result.path,
|
|
964
|
+
engram_count: result.engram_count,
|
|
965
|
+
integrity: result.integrity,
|
|
966
|
+
match_terms: result.match_terms,
|
|
967
|
+
privacy_clean: result.privacy.clean,
|
|
968
|
+
privacy_issues: result.privacy.issues.length,
|
|
969
|
+
name
|
|
970
|
+
};
|
|
907
971
|
}
|
|
908
972
|
}
|
|
909
973
|
];
|
|
@@ -911,7 +975,7 @@ Include at least one engram_suggestion if ANYTHING was learned. An empty suggest
|
|
|
911
975
|
|
|
912
976
|
// src/server.ts
|
|
913
977
|
import { z } from "zod";
|
|
914
|
-
var VERSION = "0.
|
|
978
|
+
var VERSION = "0.7.0";
|
|
915
979
|
var INSTRUCTIONS = `PLUR is your persistent memory. Corrections, preferences, and conventions persist across sessions as engrams.
|
|
916
980
|
|
|
917
981
|
REQUIRED at session boundaries:
|
|
@@ -927,6 +991,8 @@ OPTIONAL but improves quality:
|
|
|
927
991
|
- Call plur_feedback to rate which injected engrams helped (positive/negative)
|
|
928
992
|
- Call plur_recall_hybrid before answering factual questions \u2014 the answer may be in memory
|
|
929
993
|
|
|
994
|
+
For combined search (engrams + files): call plur_recall_hybrid for memories, then datacore.search for journal/knowledge files.
|
|
995
|
+
|
|
930
996
|
Do not ask permission to use these tools \u2014 they are your memory system.
|
|
931
997
|
|
|
932
998
|
Setup: If this is a fresh install, suggest the user run: npx @plur-ai/cli init
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plur-ai/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"plur-mcp": "dist/index.js"
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"dependencies": {
|
|
13
13
|
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
14
14
|
"zod": "^3.23.0",
|
|
15
|
-
"@plur-ai/core": "0.
|
|
15
|
+
"@plur-ai/core": "0.7.0"
|
|
16
16
|
},
|
|
17
17
|
"devDependencies": {
|
|
18
18
|
"@types/node": "^25.5.0"
|