prism-mcp-server 20.2.0 → 20.2.1
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 +18 -1
- package/dist/cli.js +1 -1
- package/dist/config.js +2 -1
- package/dist/connect.js +6 -1
- package/dist/storage/index.js +11 -1
- package/dist/storage/inferMetricsLedger.js +17 -2
- package/dist/storage/sqlite.js +1 -1
- package/dist/utils/entitlements.js +6 -2
- package/dist/utils/synaluxJwt.js +7 -3
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -18,6 +18,18 @@ A paid subscription adds cloud sync, higher model tiers, and team features throu
|
|
|
18
18
|
|
|
19
19
|
---
|
|
20
20
|
|
|
21
|
+
## What's New in v20.2.1
|
|
22
|
+
|
|
23
|
+
### Subscription-Aware Memory Storage
|
|
24
|
+
`prism connect` now carries an explicit `PRISM_STORAGE=auto|local|synalux|supabase`
|
|
25
|
+
into every managed host registration and rejects invalid values before changing a
|
|
26
|
+
config file. In `auto`, a portal-confirmed free tier uses local SQLite, while
|
|
27
|
+
Standard, Advanced, and Enterprise use Synalux cloud memory. If entitlement
|
|
28
|
+
resolution is unavailable, Prism fails closed instead of splitting history across
|
|
29
|
+
backends. Storage remains independent of local-first model routing.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
21
33
|
## What's New in v20.2.0
|
|
22
34
|
|
|
23
35
|
### One Command Connects Every Supported Host
|
|
@@ -124,6 +136,11 @@ an entry previously created by Prism; custom entries remain untouched.
|
|
|
124
136
|
Close the target MCP hosts before a non-dry-run registration so they cannot
|
|
125
137
|
edit their configuration at the same time.
|
|
126
138
|
|
|
139
|
+
Set `PRISM_STORAGE` before running `prism connect` to preserve an explicit
|
|
140
|
+
storage choice in the generated host entries. This does not change local-model
|
|
141
|
+
routing; Synalux cloud storage separately requires an active cloud-memory
|
|
142
|
+
entitlement.
|
|
143
|
+
|
|
127
144
|
Codex registration preserves `~/.codex/config.toml` and appends only a marked
|
|
128
145
|
Prism-managed block. `CODEX_HOME` is respected when set and must already exist,
|
|
129
146
|
matching Codex's own contract. Restart Codex CLI, the
|
|
@@ -692,7 +709,7 @@ Routing is automatic: `9b → 4b → cloud fallback` on desktop/server, `2b →
|
|
|
692
709
|
| `PRISM_FORCE_LOCAL` | Force local SQLite regardless of credentials | `false` |
|
|
693
710
|
| `TELEMETRY_WRITE_TOKEN` | Portal analytics token (optional — metrics display works without it) | -- |
|
|
694
711
|
|
|
695
|
-
With no variables set, Prism runs fully local.
|
|
712
|
+
With no variables set, Prism runs fully local. With an active cloud-memory subscription, set `PRISM_SYNALUX_API_KEY` (and leave `PRISM_STORAGE=auto`) to use the Synalux backend; a portal-confirmed free tier remains on local SQLite.
|
|
696
713
|
|
|
697
714
|
---
|
|
698
715
|
|
package/dist/cli.js
CHANGED
|
@@ -67,7 +67,7 @@ program
|
|
|
67
67
|
console.log('\nDry run complete — no files changed.');
|
|
68
68
|
}
|
|
69
69
|
if (!summary.usedApiKey) {
|
|
70
|
-
console.log('PRISM_SYNALUX_API_KEY is not set;
|
|
70
|
+
console.log('PRISM_SYNALUX_API_KEY is not set; no Synalux subscription key was copied into new registrations.');
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
73
|
catch (err) {
|
package/dist/config.js
CHANGED
|
@@ -81,7 +81,8 @@ export const GOOGLE_SEARCH_CX = process.env.GOOGLE_SEARCH_CX;
|
|
|
81
81
|
//
|
|
82
82
|
// Auto-resolution (PRISM_STORAGE=auto, the default) picks in this order:
|
|
83
83
|
// 1. PRISM_FORCE_LOCAL=true → "local" (override everything)
|
|
84
|
-
// 2.
|
|
84
|
+
// 2. Synalux credentials + portal-confirmed cloud-memory entitlement → "synalux"
|
|
85
|
+
// (portal-confirmed free → "local"; unverifiable entitlement → fail closed)
|
|
85
86
|
// 3. SUPABASE_URL + SUPABASE_KEY set → "supabase" (legacy)
|
|
86
87
|
// 4. else → "local"
|
|
87
88
|
export const PRISM_STORAGE = process.env.PRISM_STORAGE || "auto";
|
package/dist/connect.js
CHANGED
|
@@ -25,6 +25,7 @@ const HOST_ALIASES = {
|
|
|
25
25
|
};
|
|
26
26
|
const CODEX_MANAGED_START = "# >>> prism connect managed: prism-mcp";
|
|
27
27
|
const CODEX_MANAGED_END = "# <<< prism connect managed: prism-mcp";
|
|
28
|
+
const CONNECT_STORAGE_BACKENDS = ["auto", "local", "synalux", "supabase"];
|
|
28
29
|
export function normalizeHostName(value) {
|
|
29
30
|
const normalized = value.trim().toLowerCase();
|
|
30
31
|
const host = HOST_ALIASES[normalized];
|
|
@@ -208,10 +209,14 @@ function executableExists(name, platform, pathEnv) {
|
|
|
208
209
|
return false;
|
|
209
210
|
}
|
|
210
211
|
function buildMcpEntry(nodePath, serverPath, env) {
|
|
212
|
+
const storage = env.PRISM_STORAGE ?? "auto";
|
|
213
|
+
if (!CONNECT_STORAGE_BACKENDS.includes(storage)) {
|
|
214
|
+
throw new Error(`Invalid PRISM_STORAGE "${storage}". Choose one of: ${CONNECT_STORAGE_BACKENDS.join(", ")}`);
|
|
215
|
+
}
|
|
211
216
|
const serverEnv = {
|
|
212
217
|
PRISM_INSTANCE: "prism-mcp",
|
|
213
218
|
PRISM_SYNALUX_BASE_URL: env.PRISM_SYNALUX_BASE_URL || "https://synalux.ai",
|
|
214
|
-
PRISM_STORAGE:
|
|
219
|
+
PRISM_STORAGE: storage,
|
|
215
220
|
};
|
|
216
221
|
if (env.PRISM_SYNALUX_API_KEY) {
|
|
217
222
|
serverEnv.PRISM_SYNALUX_API_KEY = env.PRISM_SYNALUX_API_KEY;
|
package/dist/storage/index.js
CHANGED
|
@@ -68,9 +68,19 @@ export async function getStorage() {
|
|
|
68
68
|
debugLog("[Prism Storage] PRISM_FORCE_LOCAL=true — forcing local SQLite");
|
|
69
69
|
}
|
|
70
70
|
// ─── Resolve "auto" → synalux > supabase > local ─────────────
|
|
71
|
+
// Synalux is eligible only when the portal is the entitlement source;
|
|
72
|
+
// direct Supabase remains an independent legacy backend.
|
|
71
73
|
if (requested === "auto") {
|
|
72
74
|
if (await ensureSynaluxCredentials()) {
|
|
73
|
-
|
|
75
|
+
const { getEntitlements } = await import("../utils/entitlements.js");
|
|
76
|
+
const entitlements = await getEntitlements();
|
|
77
|
+
const memoryEntitled = entitlements.features?.session_memory_unlimited;
|
|
78
|
+
if (entitlements.source !== "portal" || typeof memoryEntitled !== "boolean") {
|
|
79
|
+
throw new Error("[Prism Storage] Could not verify the Synalux cloud-memory entitlement. " +
|
|
80
|
+
"Refusing to fall back to another backend because that could split session history. " +
|
|
81
|
+
"Retry when Synalux is reachable or set PRISM_STORAGE=local explicitly.");
|
|
82
|
+
}
|
|
83
|
+
requested = memoryEntitled ? "synalux" : "local";
|
|
74
84
|
}
|
|
75
85
|
else if (await ensureSupabaseCredentials()) {
|
|
76
86
|
requested = "supabase";
|
|
@@ -38,6 +38,18 @@ let ensured = null;
|
|
|
38
38
|
let disabled = false;
|
|
39
39
|
let initFailures = 0;
|
|
40
40
|
const MAX_INIT_FAILURES = 3;
|
|
41
|
+
function closeClient(context) {
|
|
42
|
+
const activeClient = client;
|
|
43
|
+
client = null;
|
|
44
|
+
if (!activeClient)
|
|
45
|
+
return;
|
|
46
|
+
try {
|
|
47
|
+
activeClient.close();
|
|
48
|
+
}
|
|
49
|
+
catch (e) {
|
|
50
|
+
debugLog(`[infer-ledger] ${context} close failed: ${e instanceof Error ? e.message : e}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
41
53
|
function ensureTable() {
|
|
42
54
|
if (!ensured) {
|
|
43
55
|
ensured = (async () => {
|
|
@@ -72,7 +84,7 @@ function ensureTable() {
|
|
|
72
84
|
// the next append; only repeated failure disables for the process.
|
|
73
85
|
initFailures++;
|
|
74
86
|
ensured = null;
|
|
75
|
-
|
|
87
|
+
closeClient("init failure");
|
|
76
88
|
if (initFailures >= MAX_INIT_FAILURES)
|
|
77
89
|
disabled = true;
|
|
78
90
|
debugLog(`[infer-ledger] init failed (${initFailures}/${MAX_INIT_FAILURES}${disabled ? ", ledger disabled" : ", will retry"}): ${e instanceof Error ? e.message : e}`);
|
|
@@ -152,7 +164,10 @@ export async function queryInferMetrics(sinceTs) {
|
|
|
152
164
|
}
|
|
153
165
|
/** Test hook — reset module state so a fresh DB path/env can be exercised. */
|
|
154
166
|
export function _resetInferLedgerForTest() {
|
|
155
|
-
client
|
|
167
|
+
// Close the logical client instead of only dropping its reference.
|
|
168
|
+
// libsql 0.5.29 can still retain native prepared-statement handles until
|
|
169
|
+
// V8 GC (libsql-js#228), so this is not a synchronous file-unlock barrier.
|
|
170
|
+
closeClient("test reset");
|
|
156
171
|
ensured = null;
|
|
157
172
|
disabled = false;
|
|
158
173
|
initFailures = 0;
|
package/dist/storage/sqlite.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* SQLite Local Storage Backend (v2.0 — Step 2)
|
|
3
3
|
*
|
|
4
|
-
* Zero-cloud
|
|
4
|
+
* Zero-cloud local SQLite storage using @libsql/client (libSQL/SQLite).
|
|
5
5
|
* Data lives at ~/.prism-mcp/data.db — no account, no API keys, no network.
|
|
6
6
|
*
|
|
7
7
|
* ═══════════════════════════════════════════════════════════════════
|
|
@@ -68,7 +68,11 @@ export function clampCeiling(requested, planCeiling) {
|
|
|
68
68
|
}
|
|
69
69
|
// ── Fetch ─────────────────────────────────────────────────────────
|
|
70
70
|
async function fetchEntitlements() {
|
|
71
|
-
|
|
71
|
+
// Re-read process.env because dashboard/bootstrap configuration can inject
|
|
72
|
+
// credentials after config.ts captured its module-load constants.
|
|
73
|
+
const baseUrl = process.env.PRISM_SYNALUX_BASE_URL?.trim() || PRISM_SYNALUX_BASE_URL;
|
|
74
|
+
const apiKey = process.env.PRISM_SYNALUX_API_KEY?.trim();
|
|
75
|
+
if ((!SYNALUX_CONFIGURED && !apiKey) || !baseUrl) {
|
|
72
76
|
debugLog("[entitlements] no Synalux auth configured — free tier");
|
|
73
77
|
return { ...FREE_ENTITLEMENTS, source: "unconfigured" };
|
|
74
78
|
}
|
|
@@ -78,7 +82,7 @@ async function fetchEntitlements() {
|
|
|
78
82
|
return { ...FREE_ENTITLEMENTS, source: "fallback_free" };
|
|
79
83
|
}
|
|
80
84
|
try {
|
|
81
|
-
const url = `${
|
|
85
|
+
const url = `${baseUrl}/api/v1/prism/entitlements`;
|
|
82
86
|
const res = await fetch(url, {
|
|
83
87
|
method: "GET",
|
|
84
88
|
headers: { Authorization: `Bearer ${jwt}` },
|
package/dist/utils/synaluxJwt.js
CHANGED
|
@@ -32,7 +32,11 @@ let inFlight = null;
|
|
|
32
32
|
* Concurrent callers share a single in-flight exchange (no thundering herd).
|
|
33
33
|
*/
|
|
34
34
|
export async function getSynaluxJwt() {
|
|
35
|
-
|
|
35
|
+
// Re-read process.env because storage/dashboard configuration can inject
|
|
36
|
+
// credentials after config.ts captured its module-load constants.
|
|
37
|
+
const baseUrl = process.env.PRISM_SYNALUX_BASE_URL?.trim() || PRISM_SYNALUX_BASE_URL;
|
|
38
|
+
const apiKey = process.env.PRISM_SYNALUX_API_KEY?.trim() || PRISM_SYNALUX_API_KEY;
|
|
39
|
+
if (!baseUrl || !apiKey) {
|
|
36
40
|
return null;
|
|
37
41
|
}
|
|
38
42
|
const now = Date.now();
|
|
@@ -43,11 +47,11 @@ export async function getSynaluxJwt() {
|
|
|
43
47
|
return inFlight;
|
|
44
48
|
inFlight = (async () => {
|
|
45
49
|
try {
|
|
46
|
-
const url = `${
|
|
50
|
+
const url = `${baseUrl}/api/v1/auth/jwt`;
|
|
47
51
|
const res = await fetch(url, {
|
|
48
52
|
method: "POST",
|
|
49
53
|
headers: {
|
|
50
|
-
"Authorization": `Bearer ${
|
|
54
|
+
"Authorization": `Bearer ${apiKey}`,
|
|
51
55
|
"Content-Type": "application/json",
|
|
52
56
|
},
|
|
53
57
|
signal: AbortSignal.timeout(10_000),
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prism-mcp-server",
|
|
3
|
-
"version": "20.2.
|
|
3
|
+
"version": "20.2.1",
|
|
4
4
|
"mcpName": "io.github.dcostenco/prism-coder",
|
|
5
|
-
"description": "Prism Coder — Cognitive memory + tool-calling intelligence for AI agents. Mind Palace persistent memory (BFCL Gold Certified, 100% Tool-Call Accuracy, 114 Agent Skills, PHI Guard, Tier Enforcement, Prompt-Based Skill Routing, Zero-Search HDC/HRR retrieval, HRR Semantic Drift Detection across BCBA/Coding/AAC domains, HIPAA-hardened local-
|
|
5
|
+
"description": "Prism Coder — Cognitive memory + tool-calling intelligence for AI agents. Mind Palace persistent memory (BFCL Gold Certified, 100% Tool-Call Accuracy, 114 Agent Skills, PHI Guard, Tier Enforcement, Prompt-Based Skill Routing, Zero-Search HDC/HRR retrieval, HRR Semantic Drift Detection across BCBA/Coding/AAC domains, HIPAA-hardened local or subscription-gated Synalux storage, SLERP-optimized GRPO alignment) plus the prism-coder 1.7B–32B open-weights LLM fleet.",
|
|
6
6
|
"module": "index.ts",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"main": "dist/server.js",
|
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
"dist"
|
|
17
17
|
],
|
|
18
18
|
"scripts": {
|
|
19
|
+
"clean": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
|
|
20
|
+
"prebuild": "npm run clean",
|
|
19
21
|
"build": "tsc && npm run chmod-bins",
|
|
20
22
|
"chmod-bins": "node -e \"['dist/cli.js','dist/server.js','dist/utils/universalImporter.js'].forEach(f => { try { require('fs').chmodSync(f, 0o755); } catch (e) { console.warn('chmod skipped', f, e.message); } })\"",
|
|
21
23
|
"prepublishOnly": "npm run build",
|