prism-mcp-server 9.0.5 β†’ 9.0.6

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
@@ -725,13 +725,13 @@ The Generator strips the `console.log`, resubmits, and the next `EVALUATE` retur
725
725
 
726
726
  ## πŸ†• What's New
727
727
 
728
- > **Current release: v7.8.2 β€” Cognitive Architecture**
728
+ > **Current release: v9.0.5 β€” JWKS Auth Security Hardening**
729
729
 
730
- - 🧠 **v7.8.0 β€” Cognitive Architecture:** The biggest leap forward yet. Moved beyond flat vector search into a true cognitive architecture inspired by human brain mechanics. Episodic-to-Semantic memory consolidation (Hebbian learning), ACT-R Spreading Activation with multi-hop causal reasoning, Uncertainty-Aware Rejection Gate (your agent can say "I don't know"), and Dynamic Fast Weight Decay (semantic memories outlive episodic chatter by 2Γ—). **Your agents don't just remember; they learn.** β†’ [Cognitive Architecture](#-cognitive-architecture-v78)
731
- - 🌐 **v7.7.0 β€” Cloud-Native SSE Transport:** Full unauthenticated and authenticated Server-Sent Events MCP support for seamless network deployments.
732
- - 🩺 **v7.5.0 β€” Intent Health Dashboard + Security Hardening:** Real-time 0–100 project health scoring (staleness Γ— TODO load Γ— decisions). 10 XSS injection vectors patched. Algorithm hardened with NaN guards and score ceiling.
733
- - βš”οΈ **v7.4.0 β€” Adversarial Evaluation:** Split-brain anti-sycophancy pipeline. Generator and evaluator in isolated roles with evidence-bound findings.
734
- - 🏭 **v7.3.x β€” Dark Factory + Stability:** Fail-closed 3-gate execution pipeline. Dashboard stability and verification diagnostics.
730
+ - πŸ”’ **v9.0.5 β€” JWKS Auth Security Hardening:** JWT audience/issuer claim validation (`PRISM_JWT_AUDIENCE`, `PRISM_JWT_ISSUER`), structured error logging for JWT failures, typed `PrismAuthenticatedRequest` interface, 11 new JWKS unit tests, Smithery server card fix. Vendor-neutral β€” tested with Auth0, AgentLair, Keycloak, and custom JWKS endpoints.
731
+ - 🧠 **v9.0.0 β€” Autonomous Cognitive OS:** Token-Economic Reinforcement Learning (Surprisal Gate + Cognitive Budget), Affect-Tagged Memory (valence-scored retrieval), and Episodicβ†’Semantic Consolidation. Your agents learn compression and develop intuition. β†’ [Cognitive OS](#-autonomous-cognitive-os-v90)
732
+ - 🧠 **v7.8.0 β€” Cognitive Architecture:** Episodic-to-Semantic memory consolidation (Hebbian learning), ACT-R Spreading Activation with multi-hop causal reasoning, Uncertainty-Aware Rejection Gate, and Dynamic Fast Weight Decay. β†’ [Cognitive Architecture](#-cognitive-architecture-v78)
733
+ - 🌐 **v7.7.0 β€” Cloud-Native SSE Transport:** Full Server-Sent Events MCP support for seamless network deployments.
734
+ - βš”οΈ **v7.4.0 β€” Adversarial Evaluation:** Split-brain anti-sycophancy pipeline with evidence-bound findings.
735
735
 
736
736
  πŸ‘‰ **[Full release history β†’ CHANGELOG.md](CHANGELOG.md)** Β· **[ROADMAP β†’](ROADMAP.md)**
737
737
 
@@ -971,6 +971,9 @@ Requires `PRISM_DARK_FACTORY_ENABLED=true`.
971
971
  | `PRISM_ACTR_WEIGHT_ACTIVATION` | No | Composite score ACT-R activation weight (default: `0.3`) |
972
972
  | `PRISM_ACTR_ACCESS_LOG_RETENTION_DAYS` | No | Days before access logs are pruned by background scheduler (default: `90`) |
973
973
  | `PRISM_DARK_FACTORY_ENABLED` | No | `"true"` to enable Dark Factory autonomous pipeline tools (`session_start_pipeline`, `session_check_pipeline_status`, `session_abort_pipeline`) |
974
+ | `PRISM_JWKS_URI` | No | JWKS endpoint URL for vendor-neutral JWT auth (e.g., `https://your-tenant.auth0.com/.well-known/jwks.json`) |
975
+ | `PRISM_JWT_AUDIENCE` | No | Expected JWT `aud` claim β€” prevents cross-service token confusion |
976
+ | `PRISM_JWT_ISSUER` | No | Expected JWT `iss` claim β€” validates token origin |
974
977
 
975
978
  </details>
976
979
 
@@ -1099,10 +1102,12 @@ Prism has evolved from smart session logging into a **cognitive memory architect
1099
1102
 
1100
1103
  ## πŸ“¦ Milestones & Roadmap
1101
1104
 
1102
- > **Current: v7.8.2** β€” Cognitive Architecture ([CHANGELOG](CHANGELOG.md))
1105
+ > **Current: v9.0.5** β€” JWKS Auth Security Hardening ([CHANGELOG](CHANGELOG.md))
1103
1106
 
1104
1107
  | Release | Headline |
1105
1108
  |---------|----------|
1109
+ | **v9.0.5** | πŸ”’ JWKS Auth Security Hardening β€” audience/issuer validation, JWT failure logging, typed agent identity |
1110
+ | **v9.0** | 🧠 Autonomous Cognitive OS β€” Surprisal Gate, Cognitive Budget, Affect-Tagged Memory |
1106
1111
  | **v7.8** | 🧠 Cognitive Architecture β€” Hebbian consolidation, multi-hop reasoning, rejection gate, dynamic decay |
1107
1112
  | **v7.7** | 🌐 Cloud-Native SSE Transport |
1108
1113
  | **v7.5** | 🩺 Intent Health Dashboard + Security Hardening |
@@ -1145,7 +1150,7 @@ A: Run `npm run build && npm test`, then open the Mind Palace dashboard (`localh
1145
1150
  - **MCP client race conditions.** Some MCP clients may not finish tool enumeration before the model generates its first response, causing transient `unknown_tool` errors. This is a client-side timing issue β€” Prism's server completes the MCP handshake in ~60ms. Workaround: the server-side auto-push fallback and the startup skill's retry logic.
1146
1151
  - **No real-time sync without Supabase.** Local SQLite mode is single-machine only. Multi-device or team sync requires a Supabase backend.
1147
1152
  - **Embedding quality varies by provider.** Gemini `text-embedding-004` and OpenAI `text-embedding-3-small` produce high-quality 768-dim vectors. Prism passes `dimensions: 768` via the Matryoshka API for OpenAI models (native output is 1536-dim; this truncation is lossless and outperforms ada-002 at full 1536 dims). Ollama embeddings (e.g., `nomic-embed-text`) are usable but may reduce retrieval accuracy.
1148
- - **Dashboard is HTTP-only.** The Mind Palace dashboard at `localhost:3000` does not support HTTPS. For remote access, use a reverse proxy (nginx/Caddy) or SSH tunnel. Basic auth is available via `PRISM_DASHBOARD_USER` / `PRISM_DASHBOARD_PASS`.
1153
+ - **Dashboard is HTTP-only.** The Mind Palace dashboard at `localhost:3000` does not support HTTPS. For remote access, use a reverse proxy (nginx/Caddy) or SSH tunnel. Basic auth is available via `PRISM_DASHBOARD_USER` / `PRISM_DASHBOARD_PASS`. JWKS JWT auth is available via `PRISM_JWKS_URI` for agent-native authentication (works with Auth0, AgentLair ([llms.txt](https://agentlair.com/llms.txt)), Keycloak, Cognito, or any standard JWKS endpoint).
1149
1154
  - **Long-lived clients can accumulate zombie processes.** MCP clients that run for extended periods (e.g., Claude CLI) may leave orphaned Prism server processes. The lifecycle manager detects true orphans (PPID=1) but allows coexistence for active parent processes. Use `PRISM_INSTANCE` to isolate instances across clients.
1150
1155
  - **Migration is one-way.** Universal Import ingests sessions *into* Prism but does not export back to Claude/Gemini/OpenAI formats. Use `session_export_memory` for portable JSON/Markdown export, or the `vault` format for Obsidian/Logseq-compatible `.zip` archives.
1151
1156
  - **Export ceiling at 10,000 ledger entries.** The `session_export_memory` tool and the dashboard export button cap vault/JSON exports at 10,000 entries per project as an OOM guard. Projects exceeding this limit should use per-project exports and time-based filtering to stay within the ceiling. This limit does not affect search or context loading.
@@ -41,24 +41,39 @@ let jwksCache = null;
41
41
  export function initJWKS(uri) {
42
42
  try {
43
43
  jwksCache = createRemoteJWKSet(new URL(uri));
44
+ console.error(`[Auth] πŸ”‘ JWKS remote key set initialized: ${uri}`);
44
45
  }
45
46
  catch (err) {
46
- console.error(`Failed to initialize JWKS from ${uri}:`, err);
47
+ console.error(`[Auth] ❌ Failed to initialize JWKS from ${uri}:`, err);
47
48
  }
48
49
  }
50
+ /**
51
+ * Reset JWKS cache β€” for testing only.
52
+ * @internal
53
+ */
54
+ export function _resetJWKS(cache = null) {
55
+ jwksCache = cache;
56
+ }
57
+ /** Expose JWKS cache state for testing. @internal */
58
+ export function _getJWKSCache() {
59
+ return jwksCache;
60
+ }
49
61
  // ─────────────────────────────────────────────────────────────────
50
62
  // AUTHENTICATION CHECK
51
63
  // ─────────────────────────────────────────────────────────────────
52
64
  /**
53
65
  * Check if a request is authenticated against the provided config.
54
66
  *
55
- * Returns true if:
56
- * 1. Auth is disabled (authEnabled === false) β†’ pass-through
57
- * 2. Request has a valid, non-expired session cookie
58
- * 3. Request has valid Basic Auth credentials
67
+ * Authentication is checked in priority order:
68
+ * 1. Auth disabled (authEnabled === false) β†’ pass-through
69
+ * 2. Bearer JWT token verified against JWKS remote key set
70
+ * 3. Valid, non-expired session cookie
71
+ * 4. Valid Basic Auth credentials
59
72
  *
60
- * Side effect: expired session tokens are lazily cleaned up when
61
- * encountered, preventing unbounded memory growth.
73
+ * Side effects:
74
+ * - Expired session tokens are lazily cleaned up when encountered
75
+ * - On successful JWT verification, `req.agent_id` is set for
76
+ * downstream traceability (audit logging, access control)
62
77
  */
63
78
  export async function isAuthenticated(req, config) {
64
79
  if (!config.authEnabled)
@@ -68,14 +83,26 @@ export async function isAuthenticated(req, config) {
68
83
  if (authHeader.startsWith("Bearer ") && jwksCache) {
69
84
  try {
70
85
  const token = authHeader.slice(7);
71
- const { payload } = await jwtVerify(token, jwksCache);
72
- // Attach agent_id to the request for traceability if needed downstream
73
- req.agent_id = payload.agent_id || payload.sub;
86
+ const verifyOpts = {
87
+ clockTolerance: 30, // 30s clock skew tolerance
88
+ };
89
+ if (config.jwtAudience)
90
+ verifyOpts.audience = config.jwtAudience;
91
+ if (config.jwtIssuer)
92
+ verifyOpts.issuer = config.jwtIssuer;
93
+ const { payload } = await jwtVerify(token, jwksCache, verifyOpts);
94
+ const payloadDict = payload;
95
+ // Attach agent_id and AgentLair audit metadata to the request for downstream traceability
96
+ const authReq = req;
97
+ authReq.agent_id =
98
+ payloadDict.agent_id || payload.sub;
99
+ authReq.al_name = payloadDict.al_name;
100
+ authReq.al_audit_url = payloadDict.al_audit_url;
74
101
  return true;
75
102
  }
76
103
  catch (err) {
77
- // Verification failed β€” let it fall through or return false
78
- // console.error("JWT verification failed:", err);
104
+ const code = err.code || "UNKNOWN";
105
+ console.error(`[Auth] JWT verification failed (${code}):`, err.message);
79
106
  return false;
80
107
  }
81
108
  }
@@ -90,6 +90,8 @@ export async function startDashboardServer() {
90
90
  authUser: AUTH_USER,
91
91
  authPass: AUTH_PASS,
92
92
  activeSessions,
93
+ jwtAudience: process.env.PRISM_JWT_AUDIENCE || undefined,
94
+ jwtIssuer: process.env.PRISM_JWT_ISSUER || undefined,
93
95
  };
94
96
  // v6.5.1: Rate limiter for login endpoint β€” 5 attempts per 60 seconds per IP
95
97
  const loginRateLimiter = createRateLimiter({
@@ -141,7 +143,18 @@ return false;}
141
143
  </script></body></html>`;
142
144
  }
143
145
  if (AUTH_ENABLED) {
144
- console.error(`[Dashboard] πŸ”’ Auth enabled for user "${AUTH_USER}"`);
146
+ if (AUTH_USER) {
147
+ console.error(`[Dashboard] πŸ”’ Basic auth enabled for user "${AUTH_USER}"`);
148
+ }
149
+ if (AUTH_JWKS_URI) {
150
+ console.error(`[Dashboard] πŸ”‘ JWKS auth enabled: ${AUTH_JWKS_URI}`);
151
+ if (process.env.PRISM_JWT_AUDIENCE) {
152
+ console.error(`[Dashboard] Audience: ${process.env.PRISM_JWT_AUDIENCE}`);
153
+ }
154
+ else {
155
+ console.error(`[Dashboard] ⚠️ No PRISM_JWT_AUDIENCE set β€” any valid JWT from this JWKS will be accepted.`);
156
+ }
157
+ }
145
158
  // Security advisory: HTTP Basic Auth transmits credentials in cleartext.
146
159
  // When auth is enabled for remote access, HTTPS (reverse proxy) is strongly recommended.
147
160
  console.error(`[Dashboard] ⚠️ WARNING: Dashboard uses HTTP (not HTTPS). ` +
@@ -228,7 +241,7 @@ return false;}
228
241
  version: SERVER_CONFIG.version,
229
242
  },
230
243
  authentication: {
231
- required: false
244
+ required: AUTH_ENABLED
232
245
  },
233
246
  configSchema: {
234
247
  type: "object",
@@ -318,6 +331,17 @@ return false;}
318
331
  res.writeHead(401, { "Content-Type": "text/html; charset=utf-8" });
319
332
  return res.end(renderLoginPage());
320
333
  }
334
+ // ─── AUDIT LOGGING (JWKS / AgentLair) ───
335
+ const authReq = req;
336
+ // Log successful agent access (identified via JWKS JWT)
337
+ if (authReq.agent_id && reqUrl.pathname !== "/api/scheduler") {
338
+ let auditLog = `[Dashboard] 🚦 Access: ${req.method} ${reqUrl.pathname} by agent ${authReq.agent_id}`;
339
+ if (authReq.al_name)
340
+ auditLog += ` (${authReq.al_name})`;
341
+ if (authReq.al_audit_url)
342
+ auditLog += ` - Audit: ${authReq.al_audit_url}`;
343
+ console.error(auditLog);
344
+ }
321
345
  try {
322
346
  const url = new URL(req.url || "/", `http://${req.headers.host}`);
323
347
  // ─── SSE: MCP Transport Endpoint ───
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prism-mcp-server",
3
- "version": "9.0.5",
3
+ "version": "9.0.6",
4
4
  "mcpName": "io.github.dcostenco/prism-mcp",
5
5
  "description": "The Mind Palace for AI Agents β€” a true Cognitive Architecture with Hebbian learning (episodicβ†’semantic consolidation), ACT-R spreading activation (multi-hop causal reasoning), uncertainty-aware rejection gates (agents that know when they don't know), adversarial evaluation (anti-sycophancy), fail-closed Dark Factory pipelines, persistent memory (SQLite/Supabase), multi-agent Hivemind, time travel & visual dashboard. Zero-config local mode.",
6
6
  "module": "index.ts",