@nekzus/liop 2.4.0-alpha.25 → 2.4.0-alpha.26
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/bin/agent.js +27 -933
- package/dist/bridge.js +1 -5
- package/dist/chunk-2XHSALII.js +3 -0
- package/dist/chunk-2ZYX736J.js +2 -0
- package/dist/chunk-3WRKTVOF.js +2 -0
- package/dist/chunk-6KFKO6ZX.js +2 -0
- package/dist/chunk-6VK2XALI.js +2 -0
- package/dist/chunk-AYDF3IFZ.js +2 -0
- package/dist/chunk-CTTTLCGL.js +31 -0
- package/dist/chunk-ECRS6N33.js +4 -0
- package/dist/chunk-FDJMH4CB.js +2 -0
- package/dist/chunk-FTF6AMF6.js +0 -1
- package/dist/chunk-GWVSCZUS.js +2 -0
- package/dist/chunk-LEXMMIQI.js +15 -0
- package/dist/chunk-LM26HOJ6.js +31 -0
- package/dist/chunk-MQ5SU26J.js +2 -0
- package/dist/chunk-N35BC62H.js +2 -0
- package/dist/chunk-P6IJ3VBD.js +3 -0
- package/dist/chunk-TKLRW52V.js +2 -0
- package/dist/chunk-V35CXJQN.js +2 -0
- package/dist/chunk-WP5ER7RH.js +3 -0
- package/dist/chunk-XLVEDKM6.js +2 -0
- package/dist/chunk-Y675R34Z.js +2 -0
- package/dist/chunk-YD2AF2M6.js +46 -0
- package/dist/chunk-YLCNV764.js +3 -0
- package/dist/chunk-ZZMSFCJP.js +3 -0
- package/dist/client.js +1 -12
- package/dist/gateway.js +1 -13
- package/dist/index.js +4 -320
- package/dist/kyber-PULV7PQX.js +2 -0
- package/dist/mesh.js +1 -5
- package/dist/server.js +1 -10
- package/dist/types.js +1 -3
- package/dist/verifier-J4NQYZX5.js +2 -0
- package/dist/workers/logic-execution.js +1 -355
- package/dist/workers/zk-verifier.js +1 -275
- package/package.json +1 -1
- package/dist/chunk-3664H3CV.js +0 -136
- package/dist/chunk-3QH44NKZ.js +0 -115
- package/dist/chunk-6MYJBM2E.js +0 -818
- package/dist/chunk-7PITYWOV.js +0 -68
- package/dist/chunk-DSOB2JKM.js +0 -1507
- package/dist/chunk-ET6VRUK2.js +0 -58
- package/dist/chunk-FIVRGOA4.js +0 -280
- package/dist/chunk-IHKKWXHJ.js +0 -876
- package/dist/chunk-IK7CGWAZ.js +0 -24
- package/dist/chunk-JPWC6XG6.js +0 -941
- package/dist/chunk-K3DGJLUY.js +0 -106
- package/dist/chunk-KR5UZUEY.js +0 -98
- package/dist/chunk-NXCAFF73.js +0 -59
- package/dist/chunk-Q3FKHJ3B.js +0 -345
- package/dist/chunk-R52TZEIL.js +0 -426
- package/dist/chunk-S3RAZTEM.js +0 -807
- package/dist/chunk-V47P2AQR.js +0 -281
- package/dist/chunk-WXOWJXY6.js +0 -564
- package/dist/chunk-WXYDFCIW.js +0 -293
- package/dist/chunk-Y62GORQF.js +0 -51
- package/dist/chunk-ZP3VVXOI.js +0 -66
- package/dist/chunk-ZU3WVVLC.js +0 -3752
- package/dist/kyber-CGOA7Q6A.js +0 -3
- package/dist/verifier-55HW6AFN.js +0 -6
package/dist/chunk-WXOWJXY6.js
DELETED
|
@@ -1,564 +0,0 @@
|
|
|
1
|
-
import { MCP_LEGACY_SUPPORT_ENABLED, isLegacyRequest, MCP_PROTOCOL_VERSION_LEGACY, MCP_PROTOCOL_VERSION } from './chunk-KR5UZUEY.js';
|
|
2
|
-
import { log } from './chunk-K3DGJLUY.js';
|
|
3
|
-
import { randomUUID } from 'crypto';
|
|
4
|
-
import { serve } from '@hono/node-server';
|
|
5
|
-
import { Hono } from 'hono';
|
|
6
|
-
import { cors } from 'hono/cors';
|
|
7
|
-
|
|
8
|
-
var DEFAULT_MAX_SESSIONS_PER_IP = 10;
|
|
9
|
-
var DEFAULT_SESSION_TIMEOUT_MS = 30 * 60 * 1e3;
|
|
10
|
-
var EVICTION_INTERVAL_MS = 60 * 1e3;
|
|
11
|
-
var LiopStreamBridge = class {
|
|
12
|
-
constructor(internalServer, options = {}) {
|
|
13
|
-
this.options = options;
|
|
14
|
-
this.app = new Hono();
|
|
15
|
-
this.bridgeLogic = new LiopMcpBridge(internalServer);
|
|
16
|
-
this.activeSessions = /* @__PURE__ */ new Map();
|
|
17
|
-
this.maxSessionsPerIp = options.maxSessionsPerIp ?? DEFAULT_MAX_SESSIONS_PER_IP;
|
|
18
|
-
this.sessionTimeoutMs = options.sessionTimeoutMs ?? DEFAULT_SESSION_TIMEOUT_MS;
|
|
19
|
-
this.setupRoutes();
|
|
20
|
-
}
|
|
21
|
-
options;
|
|
22
|
-
app;
|
|
23
|
-
httpServer = null;
|
|
24
|
-
bridgeLogic;
|
|
25
|
-
activeSessions;
|
|
26
|
-
evictionTimer = null;
|
|
27
|
-
maxSessionsPerIp;
|
|
28
|
-
sessionTimeoutMs;
|
|
29
|
-
/**
|
|
30
|
-
* Creates a new per-session transport instance and wires it to the LIOPMcpBridge logic.
|
|
31
|
-
*/
|
|
32
|
-
async createSessionTransport(clientIp) {
|
|
33
|
-
const { WebStandardStreamableHTTPServerTransport } = await import('@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js');
|
|
34
|
-
const transport = new WebStandardStreamableHTTPServerTransport({
|
|
35
|
-
sessionIdGenerator: () => randomUUID(),
|
|
36
|
-
onsessioninitialized: (sessionId) => {
|
|
37
|
-
this.activeSessions.set(sessionId, {
|
|
38
|
-
transport,
|
|
39
|
-
lastActivity: Date.now(),
|
|
40
|
-
clientIp
|
|
41
|
-
});
|
|
42
|
-
log.info(
|
|
43
|
-
`[LIOP-StreamBridge] Session opened: ${sessionId} (IP: ${clientIp})`
|
|
44
|
-
);
|
|
45
|
-
}
|
|
46
|
-
});
|
|
47
|
-
transport.onmessage = async (message) => {
|
|
48
|
-
if (transport.sessionId) {
|
|
49
|
-
const entry = this.activeSessions.get(transport.sessionId);
|
|
50
|
-
if (entry) entry.lastActivity = Date.now();
|
|
51
|
-
}
|
|
52
|
-
try {
|
|
53
|
-
const result = await this.bridgeLogic.handleJsonRpcRequest(
|
|
54
|
-
message
|
|
55
|
-
);
|
|
56
|
-
if (result !== void 0) {
|
|
57
|
-
await transport.send(result);
|
|
58
|
-
}
|
|
59
|
-
} catch (err) {
|
|
60
|
-
log.info("[LIOP-StreamBridge] JSON-RPC error:", err.message);
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
|
-
transport.onclose = () => {
|
|
64
|
-
if (transport.sessionId) {
|
|
65
|
-
this.activeSessions.delete(transport.sessionId);
|
|
66
|
-
log.info(`[LIOP-StreamBridge] Session closed: ${transport.sessionId}`);
|
|
67
|
-
}
|
|
68
|
-
};
|
|
69
|
-
return transport;
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* Returns the number of active sessions for a given IP.
|
|
73
|
-
*/
|
|
74
|
-
countSessionsByIp(ip) {
|
|
75
|
-
let count = 0;
|
|
76
|
-
for (const entry of this.activeSessions.values()) {
|
|
77
|
-
if (entry.clientIp === ip) count++;
|
|
78
|
-
}
|
|
79
|
-
return count;
|
|
80
|
-
}
|
|
81
|
-
/**
|
|
82
|
-
* Extracts client IP from the request (supports X-Forwarded-For for reverse proxies).
|
|
83
|
-
*/
|
|
84
|
-
getClientIp(c) {
|
|
85
|
-
return c.req.header("x-forwarded-for")?.split(",")[0]?.trim() || c.req.header("x-real-ip") || "unknown";
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Evicts sessions that have been idle longer than the configured timeout.
|
|
89
|
-
*/
|
|
90
|
-
evictIdleSessions() {
|
|
91
|
-
const now = Date.now();
|
|
92
|
-
for (const [sessionId, entry] of this.activeSessions) {
|
|
93
|
-
if (now - entry.lastActivity > this.sessionTimeoutMs) {
|
|
94
|
-
log.info(`[LIOP-StreamBridge] Evicting idle session: ${sessionId}`);
|
|
95
|
-
entry.transport.close().catch(() => {
|
|
96
|
-
});
|
|
97
|
-
this.activeSessions.delete(sessionId);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
setupRoutes() {
|
|
102
|
-
this.app.use("*", cors());
|
|
103
|
-
if (!process.env.ZERO_TRUST_TOKEN) {
|
|
104
|
-
process.env.ZERO_TRUST_TOKEN = randomUUID();
|
|
105
|
-
log.info("=".repeat(60));
|
|
106
|
-
log.info("\u26A0\uFE0F STRICT ZERO-TRUST MODE ENABLED \u26A0\uFE0F");
|
|
107
|
-
log.info("No ZERO_TRUST_TOKEN found in environment.");
|
|
108
|
-
log.info("A secure ephemeral token has been generated for this session:");
|
|
109
|
-
log.info(`Token: ${process.env.ZERO_TRUST_TOKEN}`);
|
|
110
|
-
log.info("=".repeat(60));
|
|
111
|
-
}
|
|
112
|
-
this.app.use("/mcp", async (c, next) => {
|
|
113
|
-
const auth = c.req.header("Authorization");
|
|
114
|
-
if (!auth?.startsWith("Bearer ")) {
|
|
115
|
-
return c.json(
|
|
116
|
-
{ error: "Unauthorized: LIOP Zero-Trust Policy Enforced" },
|
|
117
|
-
401
|
|
118
|
-
);
|
|
119
|
-
}
|
|
120
|
-
const token = auth.slice(7);
|
|
121
|
-
const expectedToken = process.env.ZERO_TRUST_TOKEN;
|
|
122
|
-
if (expectedToken && token === expectedToken) {
|
|
123
|
-
await next();
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
const jwtValidator = this.bridgeLogic.getServer()?.jwtValidator;
|
|
127
|
-
if (jwtValidator) {
|
|
128
|
-
try {
|
|
129
|
-
await jwtValidator.validate(token);
|
|
130
|
-
await next();
|
|
131
|
-
return;
|
|
132
|
-
} catch (e) {
|
|
133
|
-
log.info(
|
|
134
|
-
`[LIOP-StreamBridge] JWT Validation failed: ${e.message}`
|
|
135
|
-
);
|
|
136
|
-
return c.json(
|
|
137
|
-
{
|
|
138
|
-
error: `Unauthorized: JWT Validation failed - ${e.message}`
|
|
139
|
-
},
|
|
140
|
-
401
|
|
141
|
-
);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
log.info(
|
|
145
|
-
"[LIOP-StreamBridge] ALERT: Access denied - Invalid Zero-Trust token."
|
|
146
|
-
);
|
|
147
|
-
return c.json(
|
|
148
|
-
{ error: "Unauthorized: LIOP Zero-Trust Policy Enforced" },
|
|
149
|
-
401
|
|
150
|
-
);
|
|
151
|
-
});
|
|
152
|
-
this.app.all("/mcp", async (c) => {
|
|
153
|
-
const sessionId = c.req.header("mcp-session-id");
|
|
154
|
-
if (sessionId) {
|
|
155
|
-
if (!MCP_LEGACY_SUPPORT_ENABLED) {
|
|
156
|
-
return c.json(
|
|
157
|
-
{
|
|
158
|
-
error: "Session-based routing is retired. Use stateless MCP 2026-07-28 requests."
|
|
159
|
-
},
|
|
160
|
-
404
|
|
161
|
-
);
|
|
162
|
-
}
|
|
163
|
-
const existing = this.activeSessions.get(sessionId);
|
|
164
|
-
if (!existing) {
|
|
165
|
-
return c.json({ error: "Session not found" }, 404);
|
|
166
|
-
}
|
|
167
|
-
existing.lastActivity = Date.now();
|
|
168
|
-
const response = await existing.transport.handleRequest(c.req.raw);
|
|
169
|
-
if (c.req.method === "DELETE") {
|
|
170
|
-
this.activeSessions.delete(sessionId);
|
|
171
|
-
log.info(`[LIOP-StreamBridge] Session closed (DELETE): ${sessionId}`);
|
|
172
|
-
}
|
|
173
|
-
return response;
|
|
174
|
-
}
|
|
175
|
-
const contentType = c.req.header("content-type") || "";
|
|
176
|
-
if (c.req.method === "POST" && contentType.includes("application/json")) {
|
|
177
|
-
try {
|
|
178
|
-
const body = await c.req.json();
|
|
179
|
-
if (body.method === "server/discover" || body.params?._meta || !MCP_LEGACY_SUPPORT_ENABLED) {
|
|
180
|
-
const result = await this.bridgeLogic.handleJsonRpcRequest(body);
|
|
181
|
-
if (result !== void 0) {
|
|
182
|
-
return c.json(result);
|
|
183
|
-
}
|
|
184
|
-
return c.body(null, 204);
|
|
185
|
-
}
|
|
186
|
-
} catch {
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
if (!MCP_LEGACY_SUPPORT_ENABLED) {
|
|
190
|
-
return c.json(
|
|
191
|
-
{
|
|
192
|
-
error: "Stateless MCP 2026-07-28 is active. Direct JSON-RPC POST required."
|
|
193
|
-
},
|
|
194
|
-
400
|
|
195
|
-
);
|
|
196
|
-
}
|
|
197
|
-
const clientIp = this.getClientIp(c);
|
|
198
|
-
const currentSessions = this.countSessionsByIp(clientIp);
|
|
199
|
-
if (currentSessions >= this.maxSessionsPerIp) {
|
|
200
|
-
log.info(
|
|
201
|
-
`[LIOP-StreamBridge] Rate limit hit for IP: ${clientIp} (${currentSessions} sessions)`
|
|
202
|
-
);
|
|
203
|
-
return c.json({ error: "Too Many Sessions: Rate limit exceeded" }, 429);
|
|
204
|
-
}
|
|
205
|
-
const transport = await this.createSessionTransport(clientIp);
|
|
206
|
-
return await transport.handleRequest(c.req.raw);
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
/**
|
|
210
|
-
* Starts the LiopStreamBridge HTTP server and session eviction timer.
|
|
211
|
-
*/
|
|
212
|
-
async start(port) {
|
|
213
|
-
const listenPort = port ?? this.options.port ?? 3e3;
|
|
214
|
-
this.evictionTimer = setInterval(
|
|
215
|
-
() => this.evictIdleSessions(),
|
|
216
|
-
EVICTION_INTERVAL_MS
|
|
217
|
-
);
|
|
218
|
-
return new Promise((resolve) => {
|
|
219
|
-
this.httpServer = serve(
|
|
220
|
-
{
|
|
221
|
-
fetch: this.app.fetch,
|
|
222
|
-
port: listenPort
|
|
223
|
-
},
|
|
224
|
-
(info) => {
|
|
225
|
-
log.info(
|
|
226
|
-
`[LIOP-StreamBridge] Streamable HTTP Gateway on http://localhost:${info.port}/mcp`
|
|
227
|
-
);
|
|
228
|
-
resolve();
|
|
229
|
-
}
|
|
230
|
-
);
|
|
231
|
-
});
|
|
232
|
-
}
|
|
233
|
-
/**
|
|
234
|
-
* Graceful shutdown — closes all active sessions, stops timers, and releases port.
|
|
235
|
-
*/
|
|
236
|
-
async stop() {
|
|
237
|
-
if (this.evictionTimer) {
|
|
238
|
-
clearInterval(this.evictionTimer);
|
|
239
|
-
this.evictionTimer = null;
|
|
240
|
-
}
|
|
241
|
-
for (const [id, entry] of this.activeSessions) {
|
|
242
|
-
await entry.transport.close();
|
|
243
|
-
this.activeSessions.delete(id);
|
|
244
|
-
}
|
|
245
|
-
if (this.httpServer) {
|
|
246
|
-
this.httpServer.close();
|
|
247
|
-
log.info("[LIOP-StreamBridge] HTTP ports released.");
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
};
|
|
251
|
-
|
|
252
|
-
// src/bridge/index.ts
|
|
253
|
-
var LiopMcpBridge = class {
|
|
254
|
-
constructor(source, options = {}) {
|
|
255
|
-
this.options = options;
|
|
256
|
-
if (source?.constructor?.name === "LiopServer") {
|
|
257
|
-
this.liopServer = source;
|
|
258
|
-
log.info("[LIOP-Bridge] Mode: EXPOSE (LIOP -> MCP Stdio)");
|
|
259
|
-
} else if (source?.constructor?.name === "McpServer") {
|
|
260
|
-
this.legacyMcpServer = source;
|
|
261
|
-
log.info("[LIOP-Bridge] Mode: WRAP (Legacy MCP -> LIOP Mesh)");
|
|
262
|
-
} else {
|
|
263
|
-
this.legacyMcpServer = source;
|
|
264
|
-
log.info("[LIOP-Bridge] Mode: WRAP (Inferred Legacy MCP -> LIOP Mesh)");
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
options;
|
|
268
|
-
liopServer = null;
|
|
269
|
-
legacyMcpServer = null;
|
|
270
|
-
/**
|
|
271
|
-
* Handles an incoming standard MCP JSON-RPC 2.0 payload.
|
|
272
|
-
* Pipes it to the underlying server (LIOP or Legacy MCP).
|
|
273
|
-
*/
|
|
274
|
-
async handleJsonRpcRequest(payload) {
|
|
275
|
-
const id = payload.id;
|
|
276
|
-
const method = payload.method;
|
|
277
|
-
const params = payload.params;
|
|
278
|
-
if (payload.jsonrpc !== "2.0") {
|
|
279
|
-
return this.errorResponse(id, -32600, "Invalid Request");
|
|
280
|
-
}
|
|
281
|
-
if (this.liopServer) {
|
|
282
|
-
return this.handleLiopToMcp(id, method, params);
|
|
283
|
-
}
|
|
284
|
-
if (this.legacyMcpServer && this.liopServer) {
|
|
285
|
-
return this.handleLiopToMcp(id, method, params);
|
|
286
|
-
}
|
|
287
|
-
return this.errorResponse(id, -32601, "Bridge source not configured");
|
|
288
|
-
}
|
|
289
|
-
async handleLiopToMcp(id, method, params) {
|
|
290
|
-
if (!this.liopServer) return null;
|
|
291
|
-
const isLegacy = MCP_LEGACY_SUPPORT_ENABLED && isLegacyRequest({ method, params, id });
|
|
292
|
-
if (method === "initialize") {
|
|
293
|
-
if (!MCP_LEGACY_SUPPORT_ENABLED) {
|
|
294
|
-
return this.errorResponse(id, -32601, "Method retired: initialize");
|
|
295
|
-
}
|
|
296
|
-
return this.successResponse(id, {
|
|
297
|
-
protocolVersion: MCP_PROTOCOL_VERSION_LEGACY,
|
|
298
|
-
capabilities: {
|
|
299
|
-
prompts: { listChanged: true },
|
|
300
|
-
resources: { listChanged: true },
|
|
301
|
-
tools: { listChanged: true }
|
|
302
|
-
},
|
|
303
|
-
serverInfo: this.liopServer.getServerInfo()
|
|
304
|
-
});
|
|
305
|
-
}
|
|
306
|
-
if (method === "server/discover") {
|
|
307
|
-
return this.successResponse(id, {
|
|
308
|
-
resultType: "complete",
|
|
309
|
-
supportedVersions: MCP_LEGACY_SUPPORT_ENABLED ? [MCP_PROTOCOL_VERSION, MCP_PROTOCOL_VERSION_LEGACY] : [MCP_PROTOCOL_VERSION],
|
|
310
|
-
capabilities: {
|
|
311
|
-
prompts: { listChanged: true },
|
|
312
|
-
resources: { listChanged: true },
|
|
313
|
-
tools: { listChanged: true }
|
|
314
|
-
},
|
|
315
|
-
serverInfo: this.liopServer.getServerInfo()
|
|
316
|
-
});
|
|
317
|
-
}
|
|
318
|
-
if (method === "notifications/initialized") return void 0;
|
|
319
|
-
if (method === "ping") return this.successResponse(id, {});
|
|
320
|
-
if (method === "tools/list") {
|
|
321
|
-
const tools = this.liopServer.listTools().sort((a, b) => a.name.localeCompare(b.name));
|
|
322
|
-
return this.successResponse(
|
|
323
|
-
id,
|
|
324
|
-
isLegacy ? { tools } : {
|
|
325
|
-
resultType: "complete",
|
|
326
|
-
ttlMs: 3e5,
|
|
327
|
-
cacheScope: "public",
|
|
328
|
-
tools
|
|
329
|
-
}
|
|
330
|
-
);
|
|
331
|
-
}
|
|
332
|
-
if (method === "resources/list") {
|
|
333
|
-
const resources = this.liopServer.listResources().sort((a, b) => a.uri.localeCompare(b.uri));
|
|
334
|
-
return this.successResponse(
|
|
335
|
-
id,
|
|
336
|
-
isLegacy ? { resources } : {
|
|
337
|
-
resultType: "complete",
|
|
338
|
-
ttlMs: 3e5,
|
|
339
|
-
cacheScope: "public",
|
|
340
|
-
resources
|
|
341
|
-
}
|
|
342
|
-
);
|
|
343
|
-
}
|
|
344
|
-
if (method === "prompts/list") {
|
|
345
|
-
const prompts = this.liopServer.listPrompts().sort((a, b) => a.name.localeCompare(b.name));
|
|
346
|
-
return this.successResponse(
|
|
347
|
-
id,
|
|
348
|
-
isLegacy ? { prompts } : {
|
|
349
|
-
resultType: "complete",
|
|
350
|
-
ttlMs: 3e5,
|
|
351
|
-
cacheScope: "public",
|
|
352
|
-
prompts
|
|
353
|
-
}
|
|
354
|
-
);
|
|
355
|
-
}
|
|
356
|
-
if (method === "prompts/get") {
|
|
357
|
-
if (!params?.name) {
|
|
358
|
-
return this.errorResponse(id, -32602, "Missing prompt name");
|
|
359
|
-
}
|
|
360
|
-
try {
|
|
361
|
-
const result = await this.liopServer.getPrompt({
|
|
362
|
-
name: params.name,
|
|
363
|
-
arguments: params.arguments
|
|
364
|
-
});
|
|
365
|
-
return this.successResponse(
|
|
366
|
-
id,
|
|
367
|
-
isLegacy || typeof result !== "object" || result === null ? result : { resultType: "complete", ...result }
|
|
368
|
-
);
|
|
369
|
-
} catch (err) {
|
|
370
|
-
return this.errorResponse(id, -32e3, err.message);
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
if (method === "resources/read") {
|
|
374
|
-
if (!params?.uri) {
|
|
375
|
-
return this.errorResponse(id, -32602, "Missing resource URI");
|
|
376
|
-
}
|
|
377
|
-
try {
|
|
378
|
-
const result = await this.liopServer.readResource(params.uri);
|
|
379
|
-
return this.successResponse(
|
|
380
|
-
id,
|
|
381
|
-
isLegacy ? result : typeof result === "object" && result !== null ? {
|
|
382
|
-
resultType: "complete",
|
|
383
|
-
ttlMs: 6e4,
|
|
384
|
-
cacheScope: "private",
|
|
385
|
-
...result
|
|
386
|
-
} : {
|
|
387
|
-
resultType: "complete",
|
|
388
|
-
ttlMs: 6e4,
|
|
389
|
-
cacheScope: "private",
|
|
390
|
-
contents: result
|
|
391
|
-
}
|
|
392
|
-
);
|
|
393
|
-
} catch (err) {
|
|
394
|
-
return this.errorResponse(id, -32e3, err.message);
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
if (method === "tools/call") {
|
|
398
|
-
if (!params?.name) {
|
|
399
|
-
return this.errorResponse(id, -32602, "Missing tool name");
|
|
400
|
-
}
|
|
401
|
-
const request = {
|
|
402
|
-
name: params.name,
|
|
403
|
-
arguments: params.arguments || {}
|
|
404
|
-
};
|
|
405
|
-
try {
|
|
406
|
-
const result = await this.liopServer.callTool(request);
|
|
407
|
-
const isVerified = result.isError ? true : await this.verifyZkReceipt(request, result);
|
|
408
|
-
if (!isVerified) {
|
|
409
|
-
return this.successResponse(id, {
|
|
410
|
-
content: [
|
|
411
|
-
{
|
|
412
|
-
type: "text",
|
|
413
|
-
text: "ALERT [LIOP ZERO-TRUST SHIELD] ZK Verification Failed. The mathematical ImageID does not match the original payload."
|
|
414
|
-
}
|
|
415
|
-
],
|
|
416
|
-
isError: true
|
|
417
|
-
});
|
|
418
|
-
}
|
|
419
|
-
return this.successResponse(
|
|
420
|
-
id,
|
|
421
|
-
isLegacy ? result : {
|
|
422
|
-
resultType: "complete",
|
|
423
|
-
...result
|
|
424
|
-
}
|
|
425
|
-
);
|
|
426
|
-
} catch (err) {
|
|
427
|
-
return this.errorResponse(id, -32e3, err.message);
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
return this.errorResponse(id, -32601, "Method not found");
|
|
431
|
-
}
|
|
432
|
-
successResponse(id, result) {
|
|
433
|
-
return { jsonrpc: "2.0", id, result };
|
|
434
|
-
}
|
|
435
|
-
errorResponse(id, code, message) {
|
|
436
|
-
return { jsonrpc: "2.0", id, error: { code, message } };
|
|
437
|
-
}
|
|
438
|
-
async verifyZkReceipt(request, result) {
|
|
439
|
-
if (!request.arguments?.payload || typeof request.arguments.payload !== "string") {
|
|
440
|
-
return true;
|
|
441
|
-
}
|
|
442
|
-
try {
|
|
443
|
-
const payload = request.arguments.payload;
|
|
444
|
-
const contentText = result.content[0]?.text;
|
|
445
|
-
if (contentText && typeof contentText === "string") {
|
|
446
|
-
try {
|
|
447
|
-
const data = JSON.parse(contentText);
|
|
448
|
-
if (data.image_id || data.zk_receipt) {
|
|
449
|
-
const { LiopVerifier } = await import('./verifier-55HW6AFN.js');
|
|
450
|
-
const verifier = new LiopVerifier();
|
|
451
|
-
const receiptBuf = Buffer.from(data.zk_receipt || "", "base64");
|
|
452
|
-
const isV2 = receiptBuf.length > 0 && receiptBuf[0] === 2;
|
|
453
|
-
const isAuthentic = await verifier.verifyZkReceipt(
|
|
454
|
-
Buffer.from(payload, "utf-8"),
|
|
455
|
-
data.image_id || "",
|
|
456
|
-
receiptBuf,
|
|
457
|
-
{
|
|
458
|
-
guestImageIdHex: data.guest_image_id,
|
|
459
|
-
circuitName: data.circuit_name,
|
|
460
|
-
expectedOutput: data.computation_result,
|
|
461
|
-
zkPolicy: isV2 ? "required" : "none"
|
|
462
|
-
}
|
|
463
|
-
);
|
|
464
|
-
if (!isAuthentic) {
|
|
465
|
-
return false;
|
|
466
|
-
}
|
|
467
|
-
data.audit_status = isV2 ? "VERIFIED: Groth16 Zero-Knowledge Proof Certified by LiopMcpBridge" : "VERIFIED: ZK-Receipt & ImageID Mathematically Verified by LiopMcpBridge";
|
|
468
|
-
result.content[0].text = JSON.stringify(data);
|
|
469
|
-
}
|
|
470
|
-
} catch {
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
return true;
|
|
474
|
-
} catch (e) {
|
|
475
|
-
log.info("[LIOP-Bridge] ZK-Verifier Failure:", e);
|
|
476
|
-
return false;
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
/**
|
|
480
|
-
* Connects the bridge via stdio or Mesh depending on mode.
|
|
481
|
-
*/
|
|
482
|
-
async connect() {
|
|
483
|
-
if (this.legacyMcpServer) {
|
|
484
|
-
const { LiopServer } = await import('./server.js');
|
|
485
|
-
this.liopServer = new LiopServer(
|
|
486
|
-
this.options.serverInfo || {
|
|
487
|
-
name: "liop-bridge",
|
|
488
|
-
version: "1.0.0"
|
|
489
|
-
},
|
|
490
|
-
{ security: this.options.security }
|
|
491
|
-
);
|
|
492
|
-
if (this.options.publishToMesh) {
|
|
493
|
-
await this.liopServer.connect();
|
|
494
|
-
const legacy = this.legacyMcpServer;
|
|
495
|
-
if (legacy._registeredTools) {
|
|
496
|
-
for (const [name, tool] of Object.entries(legacy._registeredTools)) {
|
|
497
|
-
const t = tool;
|
|
498
|
-
this.liopServer.tool(
|
|
499
|
-
name,
|
|
500
|
-
t.description || "",
|
|
501
|
-
t.inputSchema || {},
|
|
502
|
-
// biome-ignore lint/suspicious/noExplicitAny: Opaque legacy callback args
|
|
503
|
-
async (args) => {
|
|
504
|
-
return await t.handler(args);
|
|
505
|
-
}
|
|
506
|
-
);
|
|
507
|
-
}
|
|
508
|
-
}
|
|
509
|
-
if (legacy._registeredResources) {
|
|
510
|
-
for (const [uri, resource] of Object.entries(
|
|
511
|
-
legacy._registeredResources
|
|
512
|
-
)) {
|
|
513
|
-
const r = resource;
|
|
514
|
-
this.liopServer.resource(
|
|
515
|
-
r.name,
|
|
516
|
-
uri,
|
|
517
|
-
r.metadata?.description || "",
|
|
518
|
-
r.metadata?.mimeType || "application/octet-stream",
|
|
519
|
-
async () => {
|
|
520
|
-
const res = await r.readCallback(new URL(uri));
|
|
521
|
-
return res.contents[0].text;
|
|
522
|
-
}
|
|
523
|
-
);
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
}
|
|
527
|
-
return;
|
|
528
|
-
}
|
|
529
|
-
const readline = await import('readline');
|
|
530
|
-
const rl = readline.createInterface({
|
|
531
|
-
input: process.stdin,
|
|
532
|
-
output: process.stdout,
|
|
533
|
-
terminal: false
|
|
534
|
-
});
|
|
535
|
-
const shutdown = async () => {
|
|
536
|
-
log.info("[LIOP-Bridge] Disconnecting session...");
|
|
537
|
-
if (this.liopServer) await this.liopServer.close();
|
|
538
|
-
process.exit(0);
|
|
539
|
-
};
|
|
540
|
-
rl.on("close", shutdown);
|
|
541
|
-
process.on("SIGINT", shutdown);
|
|
542
|
-
process.on("SIGTERM", shutdown);
|
|
543
|
-
rl.on("line", async (line) => {
|
|
544
|
-
if (!line.trim()) return;
|
|
545
|
-
try {
|
|
546
|
-
const payload = JSON.parse(line);
|
|
547
|
-
const response = await this.handleJsonRpcRequest(payload);
|
|
548
|
-
if (response) {
|
|
549
|
-
process.stdout.write(`${JSON.stringify(response)}
|
|
550
|
-
`);
|
|
551
|
-
}
|
|
552
|
-
} catch (e) {
|
|
553
|
-
log.error(`[LIOP-Bridge] Error: ${e.message}`);
|
|
554
|
-
}
|
|
555
|
-
});
|
|
556
|
-
}
|
|
557
|
-
getServer() {
|
|
558
|
-
return this.liopServer;
|
|
559
|
-
}
|
|
560
|
-
};
|
|
561
|
-
|
|
562
|
-
export { LiopMcpBridge, LiopStreamBridge };
|
|
563
|
-
//# sourceMappingURL=chunk-WXOWJXY6.js.map
|
|
564
|
-
//# sourceMappingURL=chunk-WXOWJXY6.js.map
|