@letterblack/lbe-sdk 1.0.0 → 1.0.2
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 +8 -5
- package/dist/mcp-server.js +104 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,6 +6,8 @@ LBE SDK exposes a WASM-authoritative execution boundary for local AI agent
|
|
|
6
6
|
governance. JavaScript is transport only: it verifies the engine hash, passes a
|
|
7
7
|
UTF-8 JSON request into WASM, and returns the UTF-8 JSON response.
|
|
8
8
|
|
|
9
|
+
Every AI action passes through a local gate before it can execute.
|
|
10
|
+
|
|
9
11
|
Everything runs on your machine. No cloud service is required.
|
|
10
12
|
|
|
11
13
|
## Install
|
|
@@ -33,17 +35,18 @@ validation and decisions originate in `dist/lbe_engine.wasm`.
|
|
|
33
35
|
import crypto from 'node:crypto';
|
|
34
36
|
import { execute } from '@letterblack/lbe-sdk';
|
|
35
37
|
|
|
36
|
-
const
|
|
38
|
+
const buildRequest = (name, payload = {}) => ({
|
|
37
39
|
version: '1.0',
|
|
38
40
|
request_id: crypto.randomUUID(),
|
|
39
41
|
timestamp: Math.floor(Date.now() / 1000),
|
|
40
42
|
actor: { id: 'agent:local', role: 'agent' },
|
|
41
|
-
intent: { type: 'command', name
|
|
43
|
+
intent: { type: 'command', name, payload },
|
|
42
44
|
context: { workspace: process.cwd(), env: {}, history: [] },
|
|
43
45
|
constraints: { policy_mode: 'strict', timeout_ms: 5000 },
|
|
44
46
|
auth: { signature: 'provided-by-host', nonce: crypto.randomUUID() }
|
|
45
|
-
})
|
|
47
|
+
});
|
|
46
48
|
|
|
49
|
+
const output = execute(JSON.stringify(buildRequest('status')));
|
|
47
50
|
console.log(JSON.parse(output));
|
|
48
51
|
```
|
|
49
52
|
|
|
@@ -54,8 +57,8 @@ console.log(JSON.parse(output));
|
|
|
54
57
|
| `npx lbe execute --input input.json` | Execute one JSON request through WASM |
|
|
55
58
|
| `cat input.json \| npx lbe execute` | Execute from stdin |
|
|
56
59
|
|
|
57
|
-
|
|
58
|
-
|
|
60
|
+
`lbe-mcp` starts a thin MCP stdio bridge exposing one tool: `lbe_execute`.
|
|
61
|
+
It contains no governance logic; it only passes JSON into `execute(input)`.
|
|
59
62
|
|
|
60
63
|
## What ships
|
|
61
64
|
|
package/dist/mcp-server.js
CHANGED
|
@@ -1,3 +1,105 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
import { execute } from './index.js';
|
|
3
|
+
|
|
4
|
+
let buffer = Buffer.alloc(0);
|
|
5
|
+
|
|
6
|
+
function send(payload) {
|
|
7
|
+
const body = Buffer.from(JSON.stringify(payload), 'utf8');
|
|
8
|
+
process.stdout.write(`Content-Length: ${body.length}\r\n\r\n`);
|
|
9
|
+
process.stdout.write(body);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function result(id, value) {
|
|
13
|
+
send({ jsonrpc: '2.0', id, result: value });
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function error(id, code, message) {
|
|
17
|
+
send({ jsonrpc: '2.0', id, error: { code, message } });
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function handle(message) {
|
|
21
|
+
const { id, method, params } = message;
|
|
22
|
+
if (method === 'initialize') {
|
|
23
|
+
result(id, {
|
|
24
|
+
protocolVersion: params?.protocolVersion || '2024-11-05',
|
|
25
|
+
capabilities: { tools: {} },
|
|
26
|
+
serverInfo: { name: 'lbe', version: '1.0.2' }
|
|
27
|
+
});
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
if (method === 'notifications/initialized') return;
|
|
31
|
+
if (method === 'tools/list') {
|
|
32
|
+
result(id, {
|
|
33
|
+
tools: [{
|
|
34
|
+
name: 'lbe_execute',
|
|
35
|
+
description: 'Execute one canonical LBE JSON request through the local WASM boundary.',
|
|
36
|
+
inputSchema: {
|
|
37
|
+
type: 'object',
|
|
38
|
+
properties: {
|
|
39
|
+
input: {
|
|
40
|
+
type: 'object',
|
|
41
|
+
description: 'LBE execute request object. It will be serialized and passed to execute(input).'
|
|
42
|
+
},
|
|
43
|
+
input_json: {
|
|
44
|
+
type: 'string',
|
|
45
|
+
description: 'Raw JSON string to pass to execute(input). Takes precedence over input.'
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}]
|
|
50
|
+
});
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (method === 'tools/call') {
|
|
54
|
+
try {
|
|
55
|
+
if (params?.name !== 'lbe_execute') {
|
|
56
|
+
error(id, -32602, 'Unknown tool');
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const args = params.arguments || {};
|
|
60
|
+
const input = typeof args.input_json === 'string' ? args.input_json : JSON.stringify(args.input);
|
|
61
|
+
const output = execute(input);
|
|
62
|
+
result(id, {
|
|
63
|
+
content: [{ type: 'text', text: output }],
|
|
64
|
+
structuredContent: JSON.parse(output),
|
|
65
|
+
isError: false
|
|
66
|
+
});
|
|
67
|
+
} catch (err) {
|
|
68
|
+
result(id, {
|
|
69
|
+
content: [{ type: 'text', text: String(err?.message || err) }],
|
|
70
|
+
isError: true
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (id !== undefined) error(id, -32601, 'Method not found');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function pump() {
|
|
79
|
+
while (true) {
|
|
80
|
+
const headerEnd = buffer.indexOf('\r\n\r\n');
|
|
81
|
+
if (headerEnd < 0) return;
|
|
82
|
+
const header = buffer.slice(0, headerEnd).toString('utf8');
|
|
83
|
+
const match = header.match(/Content-Length:\s*(\d+)/i);
|
|
84
|
+
if (!match) {
|
|
85
|
+
buffer = buffer.slice(headerEnd + 4);
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
const length = Number(match[1]);
|
|
89
|
+
const bodyStart = headerEnd + 4;
|
|
90
|
+
const bodyEnd = bodyStart + length;
|
|
91
|
+
if (buffer.length < bodyEnd) return;
|
|
92
|
+
const body = buffer.slice(bodyStart, bodyEnd).toString('utf8');
|
|
93
|
+
buffer = buffer.slice(bodyEnd);
|
|
94
|
+
try {
|
|
95
|
+
handle(JSON.parse(body));
|
|
96
|
+
} catch (err) {
|
|
97
|
+
error(null, -32700, String(err?.message || err));
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
process.stdin.on('data', (chunk) => {
|
|
103
|
+
buffer = Buffer.concat([buffer, chunk]);
|
|
104
|
+
pump();
|
|
105
|
+
});
|