prism-mcp-server 7.6.0 → 7.7.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/dist/dashboard/server.js +134 -1
- package/dist/server.js +16 -9
- package/package.json +1 -1
package/dist/dashboard/server.js
CHANGED
|
@@ -20,6 +20,8 @@ import * as http from "http";
|
|
|
20
20
|
import * as path from "path";
|
|
21
21
|
import * as os from "os";
|
|
22
22
|
import * as fs from "fs";
|
|
23
|
+
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
|
|
24
|
+
import { createServer, getAllPossibleTools } from "../server.js";
|
|
23
25
|
import { getStorage } from "../storage/index.js";
|
|
24
26
|
import { PRISM_USER_ID, SERVER_CONFIG } from "../config.js";
|
|
25
27
|
import { renderDashboardHTML } from "./ui.js";
|
|
@@ -89,6 +91,8 @@ export async function startDashboardServer() {
|
|
|
89
91
|
maxAttempts: 5,
|
|
90
92
|
windowMs: 60 * 1000,
|
|
91
93
|
});
|
|
94
|
+
// Track active SSE transports for MCP
|
|
95
|
+
const activeSSETransports = new Map();
|
|
92
96
|
/** Render a styled login page matching the Mind Palace theme */
|
|
93
97
|
function renderLoginPage() {
|
|
94
98
|
return `<!DOCTYPE html>
|
|
@@ -201,10 +205,106 @@ return false;}
|
|
|
201
205
|
});
|
|
202
206
|
return res.end(JSON.stringify({ ok: true }));
|
|
203
207
|
}
|
|
208
|
+
// ─── API: Smithery MCP Server Card (v7.4) ───
|
|
209
|
+
// Smithery explicitly requests this file to skip slow stdio scanning.
|
|
210
|
+
// MUST BE PLACED HERE (above Auth Gate) so it is a fully public manifest.
|
|
211
|
+
if (reqUrl.pathname === "/.well-known/mcp/server-card.json" && req.method === "GET") {
|
|
212
|
+
try {
|
|
213
|
+
const tools = getAllPossibleTools();
|
|
214
|
+
res.writeHead(200, {
|
|
215
|
+
"Content-Type": "application/json",
|
|
216
|
+
"Access-Control-Allow-Origin": "*",
|
|
217
|
+
"Cache-Control": "public, max-age=3600"
|
|
218
|
+
});
|
|
219
|
+
return res.end(JSON.stringify({
|
|
220
|
+
$schema: "https://smithery.ai/schema/server-card.json",
|
|
221
|
+
serverInfo: {
|
|
222
|
+
name: SERVER_CONFIG.name,
|
|
223
|
+
version: SERVER_CONFIG.version,
|
|
224
|
+
},
|
|
225
|
+
authentication: {
|
|
226
|
+
required: false
|
|
227
|
+
},
|
|
228
|
+
configSchema: {
|
|
229
|
+
type: "object",
|
|
230
|
+
required: [],
|
|
231
|
+
properties: {
|
|
232
|
+
braveApiKey: {
|
|
233
|
+
type: "string",
|
|
234
|
+
title: "Brave Search API Key",
|
|
235
|
+
description: "API key for Brave Search (powers web search and research tools). Get one at https://brave.com/search/api/"
|
|
236
|
+
},
|
|
237
|
+
googleApiKey: {
|
|
238
|
+
type: "string",
|
|
239
|
+
title: "Google AI API Key",
|
|
240
|
+
description: "API key for Google AI Studio / Gemini (powers synthesis, embeddings, paper analysis). Get one at https://aistudio.google.com/apikey"
|
|
241
|
+
},
|
|
242
|
+
storage: {
|
|
243
|
+
type: "string",
|
|
244
|
+
title: "Storage Backend",
|
|
245
|
+
description: "Storage backend: 'local' (SQLite, zero-config) or 'supabase' (PostgreSQL, multi-device)",
|
|
246
|
+
default: "local",
|
|
247
|
+
enum: ["local", "supabase"]
|
|
248
|
+
},
|
|
249
|
+
supabaseUrl: {
|
|
250
|
+
type: "string",
|
|
251
|
+
title: "Supabase URL",
|
|
252
|
+
description: "Your Supabase project URL (required if storage is 'supabase')"
|
|
253
|
+
},
|
|
254
|
+
supabaseServiceKey: {
|
|
255
|
+
type: "string",
|
|
256
|
+
title: "Supabase Service Key",
|
|
257
|
+
description: "Your Supabase service role key (required if storage is 'supabase')"
|
|
258
|
+
},
|
|
259
|
+
firecrawlApiKey: {
|
|
260
|
+
type: "string",
|
|
261
|
+
title: "Firecrawl API Key",
|
|
262
|
+
description: "Optional: API key for Firecrawl (enables Web Scholar pipeline). Get one at https://www.firecrawl.dev/"
|
|
263
|
+
},
|
|
264
|
+
braveAnswersApiKey: {
|
|
265
|
+
type: "string",
|
|
266
|
+
title: "Brave Answers API Key",
|
|
267
|
+
description: "Optional: Separate key for AI-grounded answers (brave_answers tool)"
|
|
268
|
+
},
|
|
269
|
+
prismEnableHivemind: {
|
|
270
|
+
type: "boolean",
|
|
271
|
+
title: "Enable Multi-Agent Hivemind",
|
|
272
|
+
description: "Set to true to enable multi-agent coordination tools.",
|
|
273
|
+
default: false
|
|
274
|
+
},
|
|
275
|
+
prismDarkFactoryEnabled: {
|
|
276
|
+
type: "boolean",
|
|
277
|
+
title: "Enable Dark Factory",
|
|
278
|
+
description: "Set to true to enable autonomous evaluation pipelines.",
|
|
279
|
+
default: false
|
|
280
|
+
},
|
|
281
|
+
prismTaskRouterEnabled: {
|
|
282
|
+
type: "boolean",
|
|
283
|
+
title: "Enable Task Router",
|
|
284
|
+
description: "Set to true to allow Prism to route tasks to local Ollama agents.",
|
|
285
|
+
default: false
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
},
|
|
289
|
+
tools: tools.map(t => ({
|
|
290
|
+
name: t.name,
|
|
291
|
+
description: t.description,
|
|
292
|
+
inputSchema: t.inputSchema
|
|
293
|
+
})),
|
|
294
|
+
prompts: [],
|
|
295
|
+
resources: []
|
|
296
|
+
}));
|
|
297
|
+
}
|
|
298
|
+
catch (err) {
|
|
299
|
+
console.error("[Dashboard] Error generating server card:", err);
|
|
300
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
301
|
+
return res.end(JSON.stringify({ error: err.message || "Failed to generate server card" }));
|
|
302
|
+
}
|
|
303
|
+
}
|
|
204
304
|
// ─── v5.1: Auth gate — block unauthenticated requests ───
|
|
205
305
|
if (AUTH_ENABLED && !isAuthenticated(req, authConfig)) {
|
|
206
306
|
// For API calls, return 401 JSON
|
|
207
|
-
if (reqUrl.pathname.startsWith("/api/")) {
|
|
307
|
+
if (reqUrl.pathname.startsWith("/api/") || reqUrl.pathname === "/sse" || reqUrl.pathname === "/messages") {
|
|
208
308
|
res.writeHead(401, { "Content-Type": "application/json" });
|
|
209
309
|
return res.end(JSON.stringify({ error: "Authentication required" }));
|
|
210
310
|
}
|
|
@@ -214,6 +314,39 @@ return false;}
|
|
|
214
314
|
}
|
|
215
315
|
try {
|
|
216
316
|
const url = new URL(req.url || "/", `http://${req.headers.host}`);
|
|
317
|
+
// ─── SSE: MCP Transport Endpoint ───
|
|
318
|
+
if (url.pathname === "/sse" && req.method === "GET") {
|
|
319
|
+
const transport = new SSEServerTransport("/messages", res);
|
|
320
|
+
await transport.start();
|
|
321
|
+
activeSSETransports.set(transport.sessionId, transport);
|
|
322
|
+
transport.onclose = () => {
|
|
323
|
+
activeSSETransports.delete(transport.sessionId);
|
|
324
|
+
};
|
|
325
|
+
try {
|
|
326
|
+
const mcpServer = createServer();
|
|
327
|
+
await mcpServer.connect(transport);
|
|
328
|
+
}
|
|
329
|
+
catch (err) {
|
|
330
|
+
console.error("[Dashboard] SSE Connection failed:", err);
|
|
331
|
+
activeSSETransports.delete(transport.sessionId);
|
|
332
|
+
}
|
|
333
|
+
return; // SSEServerTransport handles keeping the response open
|
|
334
|
+
}
|
|
335
|
+
// ─── SSE: MCP Message Receiver ───
|
|
336
|
+
if (url.pathname === "/messages" && req.method === "POST") {
|
|
337
|
+
const sessionId = url.searchParams.get("sessionId");
|
|
338
|
+
if (!sessionId) {
|
|
339
|
+
res.writeHead(400, { "Content-Type": "text/plain" });
|
|
340
|
+
return res.end("Missing sessionId");
|
|
341
|
+
}
|
|
342
|
+
const transport = activeSSETransports.get(sessionId);
|
|
343
|
+
if (!transport) {
|
|
344
|
+
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
345
|
+
return res.end("Session not found");
|
|
346
|
+
}
|
|
347
|
+
await transport.handlePostMessage(req, res);
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
217
350
|
// ─── Serve the Dashboard UI ───
|
|
218
351
|
if (url.pathname === "/" || url.pathname === "/index.html") {
|
|
219
352
|
res.writeHead(200, {
|
package/dist/server.js
CHANGED
|
@@ -254,7 +254,18 @@ export function notifyResourceUpdate(project, server) {
|
|
|
254
254
|
* - resources: memory://{project}/handoff — paperclip-attachable session state
|
|
255
255
|
* with subscribe support for live refresh
|
|
256
256
|
*/
|
|
257
|
-
export function
|
|
257
|
+
export function getAllPossibleTools() {
|
|
258
|
+
return [
|
|
259
|
+
...BASE_TOOLS,
|
|
260
|
+
...buildSessionMemoryTools([]),
|
|
261
|
+
...AGENT_REGISTRY_TOOLS,
|
|
262
|
+
SESSION_TASK_ROUTE_TOOL,
|
|
263
|
+
SESSION_START_PIPELINE_TOOL,
|
|
264
|
+
SESSION_CHECK_PIPELINE_STATUS_TOOL,
|
|
265
|
+
SESSION_ABORT_PIPELINE_TOOL
|
|
266
|
+
];
|
|
267
|
+
}
|
|
268
|
+
export function getAvailableTools() {
|
|
258
269
|
// ─── v4.1 FIX: Auto-Load via Dynamic Tool Descriptions ────────
|
|
259
270
|
// Read auto-load projects EXCLUSIVELY from dashboard config
|
|
260
271
|
// (available after initConfigStorage() in startServer).
|
|
@@ -273,21 +284,17 @@ export function createServer() {
|
|
|
273
284
|
if (autoloadList.length > 0) {
|
|
274
285
|
console.error(`[Prism] Auto-load projects (dashboard): ${autoloadList.join(', ')}`);
|
|
275
286
|
}
|
|
276
|
-
// Build the dynamic tool list with auto-load instruction injected
|
|
277
287
|
const SESSION_MEMORY_TOOLS = buildSessionMemoryTools(autoloadList);
|
|
278
|
-
|
|
279
|
-
// can enumerate the full capability set. Runtime guards in the CallTool handler
|
|
280
|
-
// still prevent execution without valid Supabase credentials.
|
|
281
|
-
const ALL_TOOLS = [
|
|
288
|
+
return [
|
|
282
289
|
...BASE_TOOLS,
|
|
283
290
|
...SESSION_MEMORY_TOOLS,
|
|
284
|
-
// v3.0: Agent Hivemind tools — only when PRISM_ENABLE_HIVEMIND=true
|
|
285
291
|
...(PRISM_ENABLE_HIVEMIND ? AGENT_REGISTRY_TOOLS : []),
|
|
286
|
-
// v7.1: Task Router tool — only when PRISM_TASK_ROUTER_ENABLED=true
|
|
287
292
|
...(getSettingSync("task_router_enabled", String(PRISM_TASK_ROUTER_ENABLED_ENV)) === "true" ? [SESSION_TASK_ROUTE_TOOL] : []),
|
|
288
|
-
// v7.3: Dark Factory pipeline tools — only when PRISM_DARK_FACTORY_ENABLED=true
|
|
289
293
|
...(PRISM_DARK_FACTORY_ENABLED ? [SESSION_START_PIPELINE_TOOL, SESSION_CHECK_PIPELINE_STATUS_TOOL, SESSION_ABORT_PIPELINE_TOOL] : []),
|
|
290
294
|
];
|
|
295
|
+
}
|
|
296
|
+
export function createServer() {
|
|
297
|
+
const ALL_TOOLS = getAvailableTools();
|
|
291
298
|
const server = new Server({
|
|
292
299
|
name: SERVER_CONFIG.name,
|
|
293
300
|
version: SERVER_CONFIG.version,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prism-mcp-server",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.7.1",
|
|
4
4
|
"mcpName": "io.github.dcostenco/prism-mcp",
|
|
5
5
|
"description": "The Mind Palace for AI Agents — adversarial evaluation (PLAN_CONTRACT→EVALUATE anti-sycophancy), fail-closed Dark Factory autonomous pipelines (3-gate parse→type→scope), persistent memory (SQLite/Supabase), ACT-R cognitive retrieval, behavioral learning & IDE rules sync, multi-agent Hivemind, time travel, visual dashboard. Zero-config local mode.",
|
|
6
6
|
"module": "index.ts",
|