@plur-ai/mcp 0.15.0 → 0.16.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
@@ -5,7 +5,7 @@ import { existsSync, readFileSync, writeFileSync, mkdirSync, readdirSync, statSy
5
5
  import { join } from "path";
6
6
  import { fileURLToPath } from "url";
7
7
  import { homedir, platform } from "os";
8
- var VERSION = "0.15.0";
8
+ var VERSION = "0.16.0";
9
9
  var HELP = `plur-mcp v${VERSION} \u2014 persistent memory for AI agents
10
10
 
11
11
  Usage:
@@ -105,7 +105,7 @@ Hooks inject engrams automatically on every first message \u2014 you do not need
105
105
 
106
106
  1. **Automatic**: Hooks inject relevant engrams on first message \u2014 no action needed
107
107
  2. **Learn**: When corrected or discovering something new, call \`plur_learn\` immediately
108
- 3. **Recall**: Before answering factual questions, call \`plur_recall_hybrid\` \u2014 check memory first
108
+ 3. **Recall**: Before answering factual questions, call \`plur_recall\` \u2014 check memory first
109
109
  4. **Feedback**: Rate injected engrams with \`plur_feedback\` (positive/negative) \u2014 trains relevance
110
110
  5. **End**: Call \`plur_session_end\` with summary + engram_suggestions \u2014 a SessionEnd hook auto-closes the lifecycle if you forget, but calling it yourself captures higher-quality learnings
111
111
 
@@ -233,13 +233,13 @@ async function runInit() {
233
233
  const installedVersion = installedByName.get(entry);
234
234
  if (!installedByName.has(entry)) {
235
235
  try {
236
- plur.installPack(join(bundledPacksDir, entry));
236
+ await plur.installPack(join(bundledPacksDir, entry));
237
237
  newPacks.push(entry);
238
238
  } catch {
239
239
  }
240
240
  } else if (bundledVersion && (!installedVersion || compareSemver(bundledVersion, installedVersion) > 0)) {
241
241
  try {
242
- plur.installPack(join(bundledPacksDir, entry));
242
+ await plur.installPack(join(bundledPacksDir, entry));
243
243
  upgradedPacks.push(
244
244
  `${entry} ${installedVersion ?? "unknown"}\u2192${bundledVersion}`
245
245
  );
@@ -285,7 +285,7 @@ async function runPacks() {
285
285
  process.exit(1);
286
286
  }
287
287
  try {
288
- const result = plur.installPack(source);
288
+ const result = await plur.installPack(source);
289
289
  process.stdout.write(`Installed pack '${result.name}' (${result.installed} engrams)
290
290
  `);
291
291
  } catch (err) {
@@ -351,7 +351,7 @@ if (arg === "packs") {
351
351
  process.exit(0);
352
352
  }
353
353
  if (arg === "serve" || arg === void 0) {
354
- const { runStdio } = await import("./server-7JVOIBJV.js");
354
+ const { runStdio } = await import("./server-VHSO4XMV.js");
355
355
  runStdio().catch((err) => {
356
356
  console.error("Failed to start PLUR MCP server:", err);
357
357
  process.exit(1);
@@ -0,0 +1,378 @@
1
+ import {
2
+ CURSOR_CORE_TOOL_NAMES,
3
+ VERSION,
4
+ getToolDefinitions,
5
+ mcpCanary,
6
+ registerFlushOnExit,
7
+ validateToolArgs
8
+ } from "./chunk-TPL7QPPO.js";
9
+
10
+ // src/server.ts
11
+ import { Server, ProtocolError, ProtocolErrorCode } from "@modelcontextprotocol/server";
12
+ import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
13
+ import { existsSync, readFileSync, writeFileSync } from "fs";
14
+ import { join } from "path";
15
+ import { homedir } from "os";
16
+ import { Plur, checkForUpdate } from "@plur-ai/core";
17
+ function serverPidPath(baseDir) {
18
+ return join(baseDir ?? join(homedir(), ".plur"), "server.pid");
19
+ }
20
+ function readEnterpriseToken(baseDir) {
21
+ const configPath = join(baseDir ?? join(homedir(), ".plur"), "config.json");
22
+ if (!existsSync(configPath)) return void 0;
23
+ try {
24
+ const cfg = JSON.parse(readFileSync(configPath, "utf8"));
25
+ const ent = cfg?.enterprise;
26
+ if (!ent || typeof ent.url !== "string" || typeof ent.token !== "string") return void 0;
27
+ return { url: ent.url, token: ent.token, username: ent.username };
28
+ } catch {
29
+ return void 0;
30
+ }
31
+ }
32
+ var _pendingReload = false;
33
+ function isPendingReload() {
34
+ return _pendingReload;
35
+ }
36
+ function clearPendingReload() {
37
+ _pendingReload = false;
38
+ }
39
+ var INSTRUCTIONS = `PLUR is your persistent memory. Corrections, preferences, and conventions persist across sessions as engrams.
40
+
41
+ PLUR is a GLOBAL tool \u2014 one MCP server, one engram store (~/.plur/), available in every project. Multi-project scoping uses domain/scope fields on engrams, not separate installations.
42
+
43
+ TOOL PROFILE: by default only the core session tools are exposed directly (lean profile). Every other plur_* operation is reachable via plur_admin: { action: "<tool name>", args: {...} } \u2014 same arguments and validation as a direct call. PLUR_TOOL_PROFILE=full exposes everything directly.
44
+
45
+ SESSION LIFECYCLE:
46
+ - With hooks installed (plur init): engrams are injected automatically on first message. You do NOT need to call plur_session_start \u2014 it happens via hooks. Just call plur_session_end before the conversation ends.
47
+ - Without hooks: call plur_session_start at the start, plur_session_end at the end.
48
+
49
+ DURING the session:
50
+ - When user corrects you ("no, use X not Y") \u2192 call plur_learn immediately
51
+ - When user states a preference ("always X", "never Y") \u2192 call plur_learn immediately
52
+ - When you discover a codebase convention or pattern \u2192 call plur_learn
53
+
54
+ SCOPE SELECTION (set scope PER engram, by content \u2014 not once per session):
55
+ A single session produces engrams that belong in different stores. Choose the
56
+ "scope" on EACH plur_learn call from what the engram is about:
57
+ - Team / engineering / architecture / shared-convention knowledge \u2192 the matching
58
+ team store scope (e.g. "group:<org>/<team>"). plur_session_start lists the
59
+ scopes this install can write to \u2014 use them.
60
+ - Personal preferences, your workflow, or details specific to one project \u2192 the
61
+ default/local scope (or "project:<name>").
62
+ - "global" is for genuinely cross-project facts only (language gotchas, tool
63
+ quirks). Do NOT let team-relevant knowledge fall back to "global" by omitting
64
+ scope \u2014 with a team store configured it never reaches the team store. If no
65
+ scope fits, prefer the project/local default over global.
66
+
67
+ OPTIONAL but improves quality:
68
+ - Call plur_feedback to rate which injected engrams helped (positive/negative)
69
+ - Call plur_recall before answering factual questions \u2014 the answer may be in memory
70
+
71
+ Do not ask permission to use these tools \u2014 they are your memory system.
72
+
73
+ Setup: If this is a fresh install, suggest the user run: npx @plur-ai/mcp init
74
+ This installs hooks for automatic injection + session management. One-time global setup.`;
75
+ var GUIDE_RESOURCE = `# PLUR \u2014 Agent Guide
76
+
77
+ ## What is PLUR?
78
+
79
+ Persistent memory for AI agents. Corrections, preferences, and conventions are stored as **engrams** \u2014 small assertions that strengthen with use and decay when irrelevant (ACT-R model). Storage is plain YAML on disk. Search is fully local (BM25 + embeddings). Zero API calls.
80
+
81
+ ## Quick Start
82
+
83
+ 1. \`plur_session_start\` \u2014 start a session, inject relevant context
84
+ 2. \`plur_learn\` \u2014 store a new learning
85
+ 3. \`plur_feedback\` \u2014 rate injected engrams
86
+ 4. \`plur_session_end\` \u2014 capture summary and new learnings
87
+
88
+ ## When to Call Each Tool
89
+
90
+ | Trigger | Tool |
91
+ |---------|------|
92
+ | Session starts | \`plur_session_start\` with task description |
93
+ | User corrects you | \`plur_learn\` with the correction |
94
+ | User states preference ("always X", "never Y") | \`plur_learn\` with scope and type |
95
+ | You used a recalled engram successfully | \`plur_feedback\` with "positive" |
96
+ | A recalled engram was wrong or irrelevant | \`plur_feedback\` with "negative" |
97
+ | User says "forget X" or a memory is outdated | \`plur_forget\` |
98
+ | You need to check what's stored | \`plur_status\` or \`plur_packs_list\` |
99
+ | User asks what memory did for them / is memory working | \`plur_receipt\` (relay its \`summary\`; activation_rate is coverage, not quality) |
100
+ | End of session | \`plur_session_end\` with summary and suggestions |
101
+
102
+ ## Tool Categories
103
+
104
+ ### Session Management
105
+ - **plur_session_start** \u2014 start a session, inject relevant context
106
+ - **plur_session_end** \u2014 end a session, capture summary and new learnings
107
+
108
+ ### Core Memory
109
+ - **plur_learn** \u2014 store a correction, preference, or convention
110
+ - **plur_recall** \u2014 hybrid search by default (BM25 + embeddings); pass mode:"keyword" for BM25-only
111
+ - **plur_feedback** \u2014 rate an engram (trains relevance)
112
+ - **plur_forget** \u2014 retire an outdated engram
113
+ - **plur_promote** \u2014 activate a candidate engram
114
+
115
+ ### Context Injection
116
+ - **plur_inject** \u2014 select engrams for a task (BM25)
117
+ - **plur_inject_hybrid** \u2014 select engrams for a task (BM25 + embeddings, recommended)
118
+
119
+ ### Episodic Timeline
120
+ - **plur_capture** \u2014 record what happened in a session
121
+ - **plur_timeline** \u2014 query past episodes
122
+
123
+ ### Knowledge Management
124
+ - **plur_ingest** \u2014 extract engrams from text content
125
+ - **plur_packs_install** \u2014 install curated engram packs
126
+ - **plur_packs_list** \u2014 list installed packs
127
+ - **plur_packs_export** \u2014 export engrams as a shareable pack
128
+
129
+ ### Multi-Store
130
+ - **plur_stores_add** \u2014 register an additional engram store
131
+ - **plur_stores_list** \u2014 list all configured stores
132
+
133
+ **Note:** Multi-store is currently config-only. Recall and inject search the primary store. Cross-store search coming in a future release.
134
+
135
+ ### Sync & Status
136
+ - **plur_sync** \u2014 sync engrams across devices via git
137
+ - **plur_sync_status** \u2014 check sync state
138
+ - **plur_status** \u2014 system health
139
+ - **plur_receipt** \u2014 counted report of what memory retrieved for the user (local, read-only)
140
+
141
+ ## Scoping
142
+
143
+ Use \`scope\` to namespace engrams per project:
144
+ - \`scope: "global"\` \u2014 applies everywhere (default)
145
+ - \`scope: "project:my-app"\` \u2014 applies only to my-app
146
+ - Scoped recall automatically includes global engrams
147
+
148
+ ## Storage
149
+
150
+ \`\`\`
151
+ ~/.plur/
152
+ \u251C\u2500\u2500 engrams.yaml # learned knowledge
153
+ \u251C\u2500\u2500 episodes.yaml # session timeline
154
+ \u2514\u2500\u2500 config.yaml # settings
155
+ \`\`\`
156
+
157
+ Override with \`PLUR_PATH\` environment variable.
158
+ `;
159
+ async function createServer(plur, options) {
160
+ const instance = plur ?? new Plur();
161
+ const tools = getToolDefinitions(options?.profile ?? "lean");
162
+ checkForUpdate("@plur-ai/mcp", VERSION, (r) => {
163
+ if (r.updateAvailable) {
164
+ console.error(`[plur] Update available: ${r.current} \u2192 ${r.latest}. Run: npx @plur-ai/mcp@latest`);
165
+ }
166
+ });
167
+ const server = new Server(
168
+ { name: "plur-mcp", version: VERSION },
169
+ {
170
+ capabilities: {
171
+ tools: {},
172
+ resources: {},
173
+ prompts: {},
174
+ logging: {}
175
+ },
176
+ instructions: INSTRUCTIONS
177
+ }
178
+ );
179
+ server.setRequestHandler("tools/list", async () => ({
180
+ tools: tools.map((t) => ({
181
+ name: t.name,
182
+ description: t.description,
183
+ inputSchema: t.inputSchema,
184
+ ...t.annotations && { annotations: t.annotations }
185
+ }))
186
+ }));
187
+ server.setRequestHandler("tools/call", async (request) => {
188
+ const tool = tools.find((t) => t.name === request.params.name);
189
+ if (!tool) {
190
+ const hidden = getToolDefinitions("full").find((t) => t.name === request.params.name);
191
+ if (hidden) {
192
+ return {
193
+ content: [{ type: "text", text: JSON.stringify({
194
+ error: `Tool "${request.params.name}" exists but is not directly callable under the current tool profile.`,
195
+ success: false,
196
+ hint: `Call it via plur_admin: { action: "${request.params.name}", args: { ... } } \u2014 same arguments, same validation, same result. To expose all tools directly, set PLUR_TOOL_PROFILE=full.`
197
+ }) }],
198
+ isError: true
199
+ };
200
+ }
201
+ return {
202
+ content: [{ type: "text", text: JSON.stringify({ error: `Unknown tool: ${request.params.name}`, success: false }) }],
203
+ isError: true
204
+ };
205
+ }
206
+ mcpCanary.tick();
207
+ try {
208
+ let args = request.params.arguments ?? {};
209
+ const validated = validateToolArgs(tool, args);
210
+ if (!validated.ok) {
211
+ return {
212
+ content: [{ type: "text", text: JSON.stringify(validated.errorPayload) }],
213
+ isError: true
214
+ };
215
+ }
216
+ args = validated.data;
217
+ const result = await tool.handler(args, instance);
218
+ let payload = result;
219
+ let resultIsError = false;
220
+ if (result && typeof result === "object" && result._isError === true) {
221
+ resultIsError = true;
222
+ const { _isError, ...rest } = result;
223
+ payload = rest;
224
+ }
225
+ return {
226
+ content: [{ type: "text", text: JSON.stringify(payload, null, 2) }],
227
+ ...resultIsError ? { isError: true } : {}
228
+ };
229
+ } catch (err) {
230
+ const message = err?.message ?? String(err);
231
+ server.sendLoggingMessage({ level: "error", data: `Tool ${request.params.name} failed: ${message}` });
232
+ return {
233
+ content: [{ type: "text", text: JSON.stringify({ error: message, success: false }) }],
234
+ isError: true
235
+ };
236
+ }
237
+ });
238
+ server.setRequestHandler("resources/list", async () => ({
239
+ resources: [
240
+ {
241
+ uri: "plur://guide",
242
+ name: "PLUR Agent Guide",
243
+ description: "Complete reference for all PLUR tools, when to use them, scoping, and storage",
244
+ mimeType: "text/markdown"
245
+ },
246
+ {
247
+ uri: "plur://status",
248
+ name: "PLUR Status",
249
+ description: "Live system health \u2014 engram count, episode count, pack count, storage path",
250
+ mimeType: "application/json"
251
+ }
252
+ ]
253
+ }));
254
+ server.setRequestHandler("resources/read", async (request) => {
255
+ const uri = request.params.uri;
256
+ if (uri === "plur://guide") {
257
+ const cursorNote = options?.profile === "cursor" || options?.profile === "lean" || options?.profile == null ? `
258
+
259
+ ## Lean tool profile (default)
260
+
261
+ Most tools above are NOT directly callable in this session \u2014 only ${[...CURSOR_CORE_TOOL_NAMES].join(", ")} are top-level tools here. Everything else in this guide is reachable through **plur_admin**: call it with \`{ action: "<tool name above>", args: {...} }\`. Set \`PLUR_TOOL_PROFILE=full\` to expose all ${getToolDefinitions("full").length} tools directly.` : "";
262
+ return {
263
+ contents: [{
264
+ uri: "plur://guide",
265
+ mimeType: "text/markdown",
266
+ text: GUIDE_RESOURCE + cursorNote
267
+ }]
268
+ };
269
+ }
270
+ if (uri === "plur://status") {
271
+ const status = await instance.status();
272
+ return {
273
+ contents: [{
274
+ uri: "plur://status",
275
+ mimeType: "application/json",
276
+ text: JSON.stringify({
277
+ engram_count: status.engram_count,
278
+ episode_count: status.episode_count,
279
+ pack_count: status.pack_count,
280
+ storage_root: status.storage_root,
281
+ version: VERSION
282
+ }, null, 2)
283
+ }]
284
+ };
285
+ }
286
+ throw new ProtocolError(ProtocolErrorCode.InvalidRequest, `Unknown resource: ${uri}`);
287
+ });
288
+ server.setRequestHandler("prompts/list", async () => ({
289
+ prompts: [
290
+ {
291
+ name: "plur-getting-started",
292
+ description: "Step-by-step guide to set up and start using PLUR memory"
293
+ },
294
+ {
295
+ name: "plur-session-start",
296
+ description: "Load relevant context for a task \u2014 call at the start of each session",
297
+ arguments: [
298
+ { name: "task", description: "Brief description of the task or goal", required: true },
299
+ { name: "scope", description: "Project scope (e.g. project:my-app)", required: false }
300
+ ]
301
+ }
302
+ ]
303
+ }));
304
+ server.setRequestHandler("prompts/get", async (request) => {
305
+ const name = request.params.name;
306
+ if (name === "plur-getting-started") {
307
+ const status = await instance.status();
308
+ return {
309
+ description: "Get started with PLUR memory",
310
+ messages: [{
311
+ role: "user",
312
+ content: {
313
+ type: "text",
314
+ text: `I just set up PLUR. Here's my current status:
315
+
316
+ - Engrams stored: ${status.engram_count}
317
+ - Episodes recorded: ${status.episode_count}
318
+ - Packs installed: ${status.pack_count}
319
+ - Storage: ${status.storage_root}
320
+
321
+ ${status.engram_count === 0 ? `I have no memories yet. Help me get started by:
322
+ 1. Teaching me a coding preference or convention (I'll use plur_learn)
323
+ 2. Then recalling it to verify it works (I'll use plur_recall)
324
+ 3. Rating the recall quality (I'll use plur_feedback)` : `I have ${status.engram_count} engrams stored. Try asking me something related to your project \u2014 I'll check my memory first.`}`
325
+ }
326
+ }]
327
+ };
328
+ }
329
+ if (name === "plur-session-start") {
330
+ const task = request.params.arguments?.task ?? "general work";
331
+ const scope = request.params.arguments?.scope;
332
+ return {
333
+ description: "Load relevant context for this session",
334
+ messages: [{
335
+ role: "user",
336
+ content: {
337
+ type: "text",
338
+ text: `Starting a new session. Task: ${task}${scope ? ` (scope: ${scope})` : ""}
339
+
340
+ Please:
341
+ 1. Call plur_recall with query "${task}"${scope ? ` and scope "${scope}"` : ""} to load relevant memories
342
+ 2. Review the recalled engrams and apply any relevant conventions or preferences
343
+ 3. If any recalled engrams are helpful, call plur_feedback with "positive"
344
+ 4. If any are irrelevant, call plur_feedback with "negative"`
345
+ }
346
+ }]
347
+ };
348
+ }
349
+ throw new ProtocolError(ProtocolErrorCode.InvalidRequest, `Unknown prompt: ${name}`);
350
+ });
351
+ return server;
352
+ }
353
+ async function runStdio() {
354
+ const envProfile = process.env.PLUR_TOOL_PROFILE;
355
+ const profile = envProfile === "full" ? "full" : envProfile === "cursor" ? "cursor" : "lean";
356
+ const server = await createServer(void 0, { profile });
357
+ registerFlushOnExit({});
358
+ try {
359
+ writeFileSync(serverPidPath(), String(process.pid));
360
+ } catch {
361
+ }
362
+ if (process.platform !== "win32") {
363
+ process.on("SIGUSR1", () => {
364
+ _pendingReload = true;
365
+ });
366
+ }
367
+ const transport = new StdioServerTransport();
368
+ await server.connect(transport);
369
+ }
370
+ export {
371
+ INSTRUCTIONS,
372
+ clearPendingReload,
373
+ createServer,
374
+ isPendingReload,
375
+ readEnterpriseToken,
376
+ runStdio,
377
+ serverPidPath
378
+ };
@@ -0,0 +1,76 @@
1
+ import { Plur } from '@plur-ai/core';
2
+
3
+ interface ToolAnnotations {
4
+ title?: string;
5
+ readOnlyHint?: boolean;
6
+ destructiveHint?: boolean;
7
+ idempotentHint?: boolean;
8
+ openWorldHint?: boolean;
9
+ }
10
+ interface ToolDefinition {
11
+ name: string;
12
+ description: string;
13
+ inputSchema: {
14
+ type: 'object';
15
+ [key: string]: unknown;
16
+ };
17
+ annotations?: ToolAnnotations;
18
+ handler: (args: Record<string, unknown>, plur: Plur) => Promise<unknown>;
19
+ }
20
+ /**
21
+ * Validate raw tool-call arguments against a ToolDefinition's inputSchema.
22
+ * Shared by the top-level CallToolRequestSchema handler (server.ts) and the
23
+ * plur_admin dispatch handler below — one validation path AND one error-
24
+ * formatting path, not two that can drift. (An earlier draft of this plan
25
+ * only shared the Zod validation and left the #297 array-bug hint / isError
26
+ * flag duplicated in server.ts alone — audit review caught that plur_admin's
27
+ * ~30 dispatched tools would silently lose both. errorPayload below is the
28
+ * fix: the full formatted error, including the `_isError` marker server.ts
29
+ * checks generically after ANY tool handler returns, not just this one.)
30
+ */
31
+ declare function validateToolArgs(tool: ToolDefinition, rawArgs: Record<string, unknown>): {
32
+ ok: true;
33
+ data: Record<string, unknown>;
34
+ } | {
35
+ ok: false;
36
+ errorPayload: {
37
+ error: string;
38
+ success: false;
39
+ received_fields: string[];
40
+ _isError: true;
41
+ };
42
+ };
43
+ type ToolProfile = 'full' | 'lean' | 'cursor';
44
+ declare const CURSOR_CORE_TOOL_NAMES: ReadonlySet<string>;
45
+ declare function getToolDefinitions(profile?: ToolProfile): ToolDefinition[];
46
+
47
+ /**
48
+ * Side-effect-free subpath export: @plur-ai/mcp/tools
49
+ *
50
+ * Importable without starting the MCP server or parsing process.argv.
51
+ * Use this to access PLUR's tool surface — names, descriptions, input schemas
52
+ * — from a consumer that re-exposes or validates the definitions without
53
+ * running the server.
54
+ */
55
+
56
+ /** Tool definition without the runtime handler — plain data, safe to serialize. */
57
+ interface ToolSchema {
58
+ name: string;
59
+ description: string;
60
+ inputSchema: {
61
+ type: 'object';
62
+ [key: string]: unknown;
63
+ };
64
+ annotations?: ToolAnnotations;
65
+ }
66
+ /**
67
+ * Return tool definitions as plain, handler-free schema objects.
68
+ *
69
+ * Useful when you need the MCP tool surface — name, description, and input
70
+ * schema — without the runtime handlers that require a live Plur instance.
71
+ * A downstream consumer that re-exposes a filtered subset can import this
72
+ * list and keep its copy in sync without duplicating schemas.
73
+ */
74
+ declare function getToolSchemas(profile?: ToolProfile): ToolSchema[];
75
+
76
+ export { CURSOR_CORE_TOOL_NAMES, type ToolAnnotations, type ToolDefinition, type ToolProfile, type ToolSchema, getToolDefinitions, getToolSchemas, validateToolArgs };
@@ -0,0 +1,21 @@
1
+ import {
2
+ CURSOR_CORE_TOOL_NAMES,
3
+ getToolDefinitions,
4
+ validateToolArgs
5
+ } from "./chunk-TPL7QPPO.js";
6
+
7
+ // src/tools-export.ts
8
+ function getToolSchemas(profile) {
9
+ return getToolDefinitions(profile).map(({ name, description, inputSchema, annotations }) => ({
10
+ name,
11
+ description,
12
+ inputSchema,
13
+ ...annotations !== void 0 ? { annotations } : {}
14
+ }));
15
+ }
16
+ export {
17
+ CURSOR_CORE_TOOL_NAMES,
18
+ getToolDefinitions,
19
+ getToolSchemas,
20
+ validateToolArgs
21
+ };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@plur-ai/mcp",
3
3
  "mcpName": "io.github.plur-ai/plur",
4
- "version": "0.15.0",
4
+ "version": "0.16.0",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "plur-mcp": "dist/index.js"
@@ -16,7 +16,7 @@
16
16
  "@modelcontextprotocol/client": "2.0.0-beta.4",
17
17
  "@modelcontextprotocol/core": "2.0.0-beta.4",
18
18
  "zod": "^3.23.0",
19
- "@plur-ai/core": "0.15.0"
19
+ "@plur-ai/core": "0.16.0"
20
20
  },
21
21
  "devDependencies": {
22
22
  "@types/node": "^25.5.0"
@@ -43,6 +43,10 @@
43
43
  ".": {
44
44
  "types": "./dist/index.d.ts",
45
45
  "import": "./dist/index.js"
46
+ },
47
+ "./tools": {
48
+ "types": "./dist/tools-export.d.ts",
49
+ "import": "./dist/tools-export.js"
46
50
  }
47
51
  },
48
52
  "scripts": {
@@ -39,7 +39,7 @@ npx @plur-ai/cli@0.9.4 packs install effective-memory
39
39
  12 engrams covering:
40
40
 
41
41
  - **Capture** — call `plur_learn` immediately on corrections; detect correction-shaped phrases.
42
- - **Recall** — `plur_recall_hybrid` before factual answers; don't confabulate.
42
+ - **Recall** — `plur_recall` before factual answers; don't confabulate.
43
43
  - **Session lifecycle** — bookend with `plur_session_start` / `plur_session_end`; `plur_feedback` on injected engrams; `plur_timeline` for long-horizon agents.
44
44
  - **Verification** — artifact-first; never bulk-mark as done from narrative text.
45
45
  - **Safety** — irreversible actions need actual user confirmation and one-item dry-runs.
@@ -90,7 +90,7 @@ engrams:
90
90
  pinned: true
91
91
  statement: >-
92
92
  Before answering factual questions about the user's project, codebase,
93
- preferences, infrastructure, or past decisions, call plur_recall_hybrid
93
+ preferences, infrastructure, or past decisions, call plur_recall
94
94
  first. The answer may already be in memory. Do not fabricate or compose
95
95
  answers from prior-conversation context — that context is often stale
96
96
  or invented.
@@ -99,10 +99,10 @@ engrams:
99
99
  queried. Recall before reasoning. The most common memory failure
100
100
  is not forgetting — it's not checking.
101
101
  domain: plur.recall
102
- tags: [recall, search, before-answering, plur_recall_hybrid, confabulation]
102
+ tags: [recall, search, before-answering, plur_recall, confabulation]
103
103
  activation: { retrieval_strength: 0.95, storage_strength: 0.95, frequency: 0, last_accessed: "2026-05-04" }
104
104
  dual_coding:
105
- example: "User asks 'how do we deploy to production?' — call plur_recall_hybrid('deployment production') before answering. You might find 'deploy requires git push to nightshift server, not GitHub' from a previous session."
105
+ example: "User asks 'how do we deploy to production?' — call plur_recall('deployment production') before answering. You might find 'deploy requires git push to nightshift server, not GitHub' from a previous session."
106
106
  analogy: "Like checking your notes before answering a question in a meeting, instead of guessing."
107
107
  pack: effective-memory
108
108
  polarity: do