prism-mcp-server 2.3.6 β†’ 2.3.8

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/README.md CHANGED
@@ -14,13 +14,15 @@
14
14
 
15
15
  ---
16
16
 
17
- ## What's New in v2.3.5 β€” AI Reasoning Engine 🧠
17
+ ## What's New in v2.3.8 β€” LangGraph Research Agent πŸ”¬
18
18
 
19
19
  | Feature | Description |
20
20
  |---|---|
21
- | πŸ•ΈοΈ **Neural Graph** | Interactive knowledge graph on the Mind Palace Dashboard β€” visualize how projects connect through shared keywords and categories using Vis.js force-directed layout. |
22
- | πŸ›‘οΈ **Prompt Injection Shield** | Gemini-powered security scan in `session_health_check` β€” detects system override attempts, jailbreaks, and data exfiltration hidden in agent memory. Tuned to avoid false positives on normal dev commands. |
23
- | 🧬 **Fact Merger** | Async LLM contradiction resolution on every handoff save β€” if old context says "Postgres" and new says "MySQL", Gemini silently merges the facts in the background. Zero latency impact (fire-and-forget). |
21
+ | πŸ€– **LangGraph Research Agent** | New `examples/langgraph-agent/` β€” a 5-node agentic research agent (planβ†’searchβ†’analyzeβ†’decideβ†’answerβ†’save) with autonomous looping, MCP integration, and persistent memory. |
22
+ | 🧠 **Agentic Memory** | `save_session` node persists research findings to a ledger β€” the agent doesn't just answer and forget. Routes to Prism's `session_save_ledger` in MCP-connected mode. |
23
+ | πŸ”Œ **MCP Client Bridge** | Raw JSON-RPC 2.0 client (`mcp_client.py`) for Python 3.9+ β€” dynamically discovers and wraps Prism MCP tools as LangChain `StructuredTool` objects. |
24
+ | πŸ”§ **Storage Abstraction Fix** | Resource/Prompt handlers now route through `getStorage()` instead of calling Supabase directly β€” eliminates EOF crashes when reading `memory://` resources. |
25
+ | πŸ›‘οΈ **Error Boundaries** | Resource handlers catch errors gracefully and return proper MCP error responses (`isError: true`) instead of crashing the server process. |
24
26
 
25
27
  <details>
26
28
  <summary><strong>What's in v2.2.0</strong></summary>
@@ -251,6 +253,39 @@ Add to your Continue `config.json` or Cline MCP settings:
251
253
 
252
254
  ---
253
255
 
256
+ ## Claude Code + Gemini Startup Compatibility
257
+
258
+ If you want consistent behavior across clients, treat startup in two phases:
259
+
260
+ 1. **Server availability**: ensure `prism-mcp` is enabled in MCP config so tools are available.
261
+ 2. **Context hydration**: explicitly call `session_load_context` at session start.
262
+
263
+ Recommended startup call:
264
+
265
+ ```json
266
+ {
267
+ "projectName": "<your-project>",
268
+ "level": "standard"
269
+ }
270
+ ```
271
+
272
+ Important distinction:
273
+
274
+ - Auto-loading `prism-mcp` makes the server available.
275
+ - It does **not** guarantee memory context is auto-hydrated unless your client runtime/hook invokes `session_load_context`.
276
+
277
+ Client notes:
278
+
279
+ - **Gemini runtimes** may support native startup execution depending on configuration.
280
+ - **Claude Code** should use a local `SessionStart` hook in `~/.claude/settings.json` for deterministic startup context loading.
281
+
282
+ Verification pattern (same for both clients):
283
+
284
+ - Print a startup marker after successful `session_load_context` (for example, `PRISM_CONTEXT_LOADED`).
285
+ - If the marker is missing, startup hydration did not run.
286
+
287
+ ---
288
+
254
289
  ## Use Cases
255
290
 
256
291
  | Scenario | How Prism MCP Helps |
package/dist/config.js CHANGED
@@ -22,7 +22,7 @@
22
22
  // multi-tenant Row Level Security (RLS) for production hosting.
23
23
  export const SERVER_CONFIG = {
24
24
  name: "prism-mcp",
25
- version: "2.3.4",
25
+ version: "2.3.7",
26
26
  };
27
27
  // ─── Required: Brave Search API Key ───────────────────────────
28
28
  export const BRAVE_API_KEY = process.env.BRAVE_API_KEY;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Mind Palace Dashboard β€” UI Renderer (v2.3.4)
2
+ * Mind Palace Dashboard β€” UI Renderer (v2.3.7)
3
3
  *
4
4
  * Pure CSS + Vanilla JS single-page dashboard.
5
5
  * No build step, no Tailwind, no framework β€” served as a template literal.
@@ -279,7 +279,7 @@ export function renderDashboardHTML() {
279
279
  <div class="logo">
280
280
  <span class="logo-icon">🧠</span>
281
281
  Prism Mind Palace
282
- <span class="version-badge">v2.3.4</span>
282
+ <span class="version-badge">v2.3.7</span>
283
283
  </div>
284
284
  <div class="selector">
285
285
  <select id="projectSelect">
package/dist/server.js CHANGED
@@ -61,12 +61,13 @@ SubscribeRequestSchema, UnsubscribeRequestSchema, } from "@modelcontextprotocol/
61
61
  import { SERVER_CONFIG, SESSION_MEMORY_ENABLED, PRISM_USER_ID } from "./config.js";
62
62
  import { getSyncBus } from "./sync/factory.js";
63
63
  import { startDashboardServer } from "./dashboard/server.js";
64
- // ─── v0.4.0: Supabase API imports for Prompts/Resources handlers ───
65
- // REVIEWER NOTE: The prompt and resource handlers need direct access
66
- // to supabaseRpc and supabaseGet to fetch context. In v0.3.0, only
67
- // the handler files imported from supabaseApi. Now server.ts needs
68
- // them too for the prompt/resource request handlers.
69
- import { supabaseRpc, supabaseGet } from "./utils/supabaseApi.js";
64
+ // ─── v2.3.6 FIX: Use Storage Abstraction for Prompts/Resources ───
65
+ // CRITICAL FIX: Previously imported supabaseRpc/supabaseGet directly,
66
+ // which bypassed the storage abstraction layer and caused the server
67
+ // to crash (EOF) when the Supabase REST call failed without a proper
68
+ // error wrapper. Now uses getStorage() which routes through the
69
+ // correct backend (Supabase or SQLite) with proper error handling.
70
+ import { getStorage } from "./storage/index.js";
70
71
  // ─── Import Tool Definitions (schemas) and Handlers (implementations) ─────
71
72
  import { WEB_SEARCH_TOOL, BRAVE_WEB_SEARCH_CODE_MODE_TOOL, LOCAL_SEARCH_TOOL, BRAVE_LOCAL_SEARCH_CODE_MODE_TOOL, CODE_MODE_TRANSFORM_TOOL, BRAVE_ANSWERS_TOOL, RESEARCH_PAPER_ANALYSIS_TOOL, webSearchHandler, braveWebSearchCodeModeHandler, localSearchHandler, braveLocalSearchCodeModeHandler, codeModeTransformHandler, braveAnswersHandler, researchPaperAnalysisHandler, } from "./tools/index.js";
72
73
  // Session memory tools β€” only used if Supabase is configured
@@ -271,14 +272,10 @@ export function createServer() {
271
272
  const project = promptArgs?.project || "default";
272
273
  const level = promptArgs?.level || "standard";
273
274
  console.error(`[prompt:resume_session] Loading ${level} context for "${project}"`);
274
- // Fetch context using the same RPC as session_load_context
275
- // v1.5.0: Pass p_user_id for multi-tenant isolation
276
- const result = await supabaseRpc("get_session_context", {
277
- p_project: project,
278
- p_level: level,
279
- p_user_id: PRISM_USER_ID,
280
- });
281
- const data = Array.isArray(result) ? result[0] : result;
275
+ // v2.3.6 FIX: Use storage abstraction instead of direct supabaseRpc
276
+ const storage = await getStorage();
277
+ const result = await storage.loadContext(project, level, PRISM_USER_ID);
278
+ const data = result;
282
279
  // REVIEWER NOTE: We include the version in the prompt text so
283
280
  // the LLM knows to pass it back when saving. This is critical
284
281
  // for OCC (Enhancement #5) to work even when context is loaded
@@ -343,28 +340,25 @@ export function createServer() {
343
340
  }));
344
341
  // List concrete resources β€” one per known project
345
342
  server.setRequestHandler(ListResourcesRequestSchema, async () => {
346
- // REVIEWER NOTE: We query Supabase for all projects that have
347
- // a handoff entry. This gives Claude Desktop a browsable list
348
- // of all projects with saved state. The select fields are
349
- // minimal to keep the response lightweight.
350
- const handoffs = await supabaseGet("session_handoffs", {
351
- select: "project,last_summary,updated_at",
352
- });
353
- return {
354
- resources: (Array.isArray(handoffs) ? handoffs : []).map((h) => ({
355
- uri: `memory://${h.project}/handoff`,
356
- name: `${h.project} β€” Session State`,
357
- description: h.last_summary
358
- ? h.last_summary.substring(0, 200)
359
- : "No summary available",
360
- mimeType: "application/json",
361
- })),
362
- };
343
+ // v2.3.6 FIX: Use storage abstraction instead of direct supabaseGet
344
+ try {
345
+ const storage = await getStorage();
346
+ const projects = await storage.listProjects();
347
+ return {
348
+ resources: projects.map((p) => ({
349
+ uri: `memory://${p}/handoff`,
350
+ name: `${p} β€” Session State`,
351
+ mimeType: "application/json",
352
+ })),
353
+ };
354
+ }
355
+ catch (error) {
356
+ console.error(`[resource:list] Error listing resources: ${error}`);
357
+ return { resources: [] };
358
+ }
363
359
  });
364
360
  // Read a specific project's handoff as a resource
365
361
  server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
366
- // REVIEWER NOTE: Parse the project name from the URI.
367
- // URI format: memory://{project}/handoff
368
362
  const uri = request.params.uri;
369
363
  const match = uri.match(/^memory:\/\/(.+)\/handoff$/);
370
364
  if (!match) {
@@ -372,32 +366,35 @@ export function createServer() {
372
366
  }
373
367
  const project = decodeURIComponent(match[1]);
374
368
  console.error(`[resource:read] Fetching handoff for "${project}"`);
375
- // Reuse the same RPC as session_load_context β€” standard level
376
- // gives a good balance of info without being too large.
377
- // REVIEWER NOTE: The RPC response includes `version` (added in
378
- // migration 019), which the LLM needs for OCC when saving later.
379
- // v1.5.0: Pass p_user_id for multi-tenant isolation
380
- const result = await supabaseRpc("get_session_context", {
381
- p_project: project,
382
- p_level: "standard",
383
- p_user_id: PRISM_USER_ID,
384
- });
385
- const data = Array.isArray(result) ? result[0] : result;
386
- // REVIEWER NOTE: Inject explicit OCC instructions into the
387
- // resource text so the LLM knows to pass version on save.
388
- const resourceData = data || { status: "no_session_found", project };
389
- if (data?.version) {
390
- resourceData._occ_instruction =
391
- `When saving handoff state, you MUST pass expected_version: ${data.version} ` +
392
- `to prevent state collisions with other sessions.`;
369
+ try {
370
+ // v2.3.6 FIX: Use storage abstraction instead of direct supabaseRpc
371
+ const storage = await getStorage();
372
+ const data = await storage.loadContext(project, "standard", PRISM_USER_ID);
373
+ const resourceData = data || { status: "no_session_found", project };
374
+ if (data?.version) {
375
+ resourceData._occ_instruction =
376
+ `When saving handoff state, you MUST pass expected_version: ${data.version} ` +
377
+ `to prevent state collisions with other sessions.`;
378
+ }
379
+ return {
380
+ contents: [{
381
+ uri: uri,
382
+ mimeType: "application/json",
383
+ text: JSON.stringify(resourceData, null, 2),
384
+ }],
385
+ };
386
+ }
387
+ catch (error) {
388
+ console.error(`[resource:read] Error reading resource ${uri}: ${error}`);
389
+ return {
390
+ isError: true,
391
+ contents: [{
392
+ uri: uri,
393
+ mimeType: "text/plain",
394
+ text: `Error reading resource: ${error instanceof Error ? error.message : String(error)}`,
395
+ }],
396
+ };
393
397
  }
394
- return {
395
- contents: [{
396
- uri: uri,
397
- mimeType: "application/json",
398
- text: JSON.stringify(resourceData, null, 2),
399
- }],
400
- };
401
398
  });
402
399
  // ─── Resource Subscriptions: subscribe/unsubscribe ───
403
400
  // REVIEWER NOTE: These handlers track which resource URIs the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prism-mcp-server",
3
- "version": "2.3.6",
3
+ "version": "2.3.8",
4
4
  "mcpName": "io.github.dcostenco/prism-mcp",
5
5
  "description": "The Mind Palace for AI Agents β€” local-first MCP server with persistent memory (SQLite/Supabase), visual dashboard, time travel, multi-agent sync, Morning Briefings, reality drift detection, code mode templates, semantic vector search, and Brave Search + Gemini analysis. Zero-config local mode.",
6
6
  "module": "index.ts",