@llui/mcp 0.0.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/LICENSE +21 -0
- package/README.md +13 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +8 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +498 -0
- package/dist/index.js.map +1 -0
- package/package.json +51 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Franco Ponticelli
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# @llui/mcp
|
|
2
|
+
|
|
3
|
+
[Model Context Protocol](https://spec.modelcontextprotocol.io/) server for [LLui](https://github.com/fponticelli/llui).
|
|
4
|
+
|
|
5
|
+
Exposes LLui debug tools as MCP resources for LLM-assisted development.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add -D @llui/mcp
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## License
|
|
12
|
+
|
|
13
|
+
MIT
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { LluiMcpServer } from './index.js';
|
|
3
|
+
const port = Number(process.env.LLUI_MCP_PORT ?? 5200);
|
|
4
|
+
const server = new LluiMcpServer(port);
|
|
5
|
+
server.startBridge();
|
|
6
|
+
server.start();
|
|
7
|
+
process.stderr.write(`[llui-mcp] listening on stdio; bridge ws://127.0.0.1:${port}\n`);
|
|
8
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE1C,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,IAAI,CAAC,CAAA;AACtD,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC,IAAI,CAAC,CAAA;AACtC,MAAM,CAAC,WAAW,EAAE,CAAA;AACpB,MAAM,CAAC,KAAK,EAAE,CAAA;AACd,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,wDAAwD,IAAI,IAAI,CAAC,CAAA"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { LluiDebugAPI } from '@llui/dom';
|
|
2
|
+
interface McpToolDefinition {
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
inputSchema: {
|
|
6
|
+
type: 'object';
|
|
7
|
+
properties: Record<string, unknown>;
|
|
8
|
+
required?: string[];
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
declare const TOOLS: McpToolDefinition[];
|
|
12
|
+
export declare class LluiMcpServer {
|
|
13
|
+
/** Direct (same-process) debug API, used for tests or in-process bridging. */
|
|
14
|
+
private debugApi;
|
|
15
|
+
/** Bridge (WebSocket) state for out-of-process browser connection. */
|
|
16
|
+
private wsServer;
|
|
17
|
+
private browserWs;
|
|
18
|
+
private pending;
|
|
19
|
+
private bridgePort;
|
|
20
|
+
constructor(bridgePort?: number);
|
|
21
|
+
/** Connect to a debug API instance directly (for in-process usage). */
|
|
22
|
+
connectDirect(api: LluiDebugAPI): void;
|
|
23
|
+
/**
|
|
24
|
+
* Start a WebSocket server on the configured bridge port. The browser-side
|
|
25
|
+
* relay (injected by the Vite plugin in dev mode) connects here and forwards
|
|
26
|
+
* debug-API calls.
|
|
27
|
+
*/
|
|
28
|
+
startBridge(): void;
|
|
29
|
+
stopBridge(): void;
|
|
30
|
+
/** Invoke a debug API method — over the bridge if connected, else direct. */
|
|
31
|
+
private call;
|
|
32
|
+
/** Get tool definitions for MCP handshake */
|
|
33
|
+
getTools(): McpToolDefinition[];
|
|
34
|
+
/** Handle an MCP tool call */
|
|
35
|
+
handleToolCall(name: string, args: Record<string, unknown>): Promise<unknown>;
|
|
36
|
+
/** Start the MCP server on stdin/stdout */
|
|
37
|
+
start(): void;
|
|
38
|
+
private handleRequest;
|
|
39
|
+
}
|
|
40
|
+
export { TOOLS as mcpToolDefinitions };
|
|
41
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAM7C,UAAU,iBAAiB;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ,CAAA;QACd,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QACnC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;KACpB,CAAA;CACF;AAkBD,QAAA,MAAM,KAAK,EAAE,iBAAiB,EAuQ7B,CAAA;AASD,qBAAa,aAAa;IACxB,8EAA8E;IAC9E,OAAO,CAAC,QAAQ,CAA4B;IAC5C,sEAAsE;IACtE,OAAO,CAAC,QAAQ,CAA+B;IAC/C,OAAO,CAAC,SAAS,CAAyB;IAC1C,OAAO,CAAC,OAAO,CAAoC;IACnD,OAAO,CAAC,UAAU,CAAQ;gBAEd,UAAU,SAAO;IAI7B,uEAAuE;IACvE,aAAa,CAAC,GAAG,EAAE,YAAY,GAAG,IAAI;IAItC;;;;OAIG;IACH,WAAW,IAAI,IAAI;IAwBnB,UAAU,IAAI,IAAI;IAQlB,6EAA6E;YAC/D,IAAI;IAmBlB,6CAA6C;IAC7C,QAAQ,IAAI,iBAAiB,EAAE;IAI/B,8BAA8B;IACxB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC;IA+FnF,2CAA2C;IAC3C,KAAK,IAAI,IAAI;YAuBC,aAAa;CAsD5B;AAED,OAAO,EAAE,KAAK,IAAI,kBAAkB,EAAE,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,498 @@
|
|
|
1
|
+
import { WebSocketServer } from 'ws';
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
|
+
// ── Tool Definitions ────────────────────────────────────────────
|
|
4
|
+
const TOOLS = [
|
|
5
|
+
{
|
|
6
|
+
name: 'llui_get_state',
|
|
7
|
+
description: 'Get the current state of the LLui component. Returns a JSON-serializable state object.',
|
|
8
|
+
inputSchema: {
|
|
9
|
+
type: 'object',
|
|
10
|
+
properties: {
|
|
11
|
+
component: {
|
|
12
|
+
type: 'string',
|
|
13
|
+
description: 'Component name (defaults to root)',
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
name: 'llui_send_message',
|
|
20
|
+
description: 'Send a message to the component and return the new state and effects. Validates the message first. Calls flush() automatically.',
|
|
21
|
+
inputSchema: {
|
|
22
|
+
type: 'object',
|
|
23
|
+
properties: {
|
|
24
|
+
msg: {
|
|
25
|
+
type: 'object',
|
|
26
|
+
description: 'The message to send (must be a valid Msg variant)',
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
required: ['msg'],
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: 'llui_eval_update',
|
|
34
|
+
description: 'Dry-run: call update(state, msg) without applying. Returns what the new state and effects would be without modifying the running app.',
|
|
35
|
+
inputSchema: {
|
|
36
|
+
type: 'object',
|
|
37
|
+
properties: {
|
|
38
|
+
msg: {
|
|
39
|
+
type: 'object',
|
|
40
|
+
description: 'The hypothetical message to evaluate',
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
required: ['msg'],
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: 'llui_validate_message',
|
|
48
|
+
description: 'Validate a message against the component Msg type. Returns errors or null if valid.',
|
|
49
|
+
inputSchema: {
|
|
50
|
+
type: 'object',
|
|
51
|
+
properties: {
|
|
52
|
+
msg: {
|
|
53
|
+
type: 'object',
|
|
54
|
+
description: 'The message to validate',
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
required: ['msg'],
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
name: 'llui_get_message_history',
|
|
62
|
+
description: 'Get the chronological message history with state transitions, effects, and dirty masks. Supports pagination via `since` (exclusive, return entries with index > since) and `limit` (return at most N most-recent entries). Use both together for tail-fetching.',
|
|
63
|
+
inputSchema: {
|
|
64
|
+
type: 'object',
|
|
65
|
+
properties: {
|
|
66
|
+
since: {
|
|
67
|
+
type: 'number',
|
|
68
|
+
description: 'Return entries with index strictly greater than this.',
|
|
69
|
+
},
|
|
70
|
+
limit: {
|
|
71
|
+
type: 'number',
|
|
72
|
+
description: 'Max entries to return (the N most recent).',
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
name: 'llui_export_trace',
|
|
79
|
+
description: 'Export the current session as a replayable LluiTrace JSON.',
|
|
80
|
+
inputSchema: {
|
|
81
|
+
type: 'object',
|
|
82
|
+
properties: {},
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
name: 'llui_get_bindings',
|
|
87
|
+
description: 'Get all active reactive bindings with their masks, last values, and DOM targets.',
|
|
88
|
+
inputSchema: {
|
|
89
|
+
type: 'object',
|
|
90
|
+
properties: {
|
|
91
|
+
filter: {
|
|
92
|
+
type: 'string',
|
|
93
|
+
description: 'Filter by DOM selector or mask value',
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
name: 'llui_why_did_update',
|
|
100
|
+
description: 'Explain why a specific binding re-evaluated: which mask bits were dirty, what the accessor returned, what the previous value was.',
|
|
101
|
+
inputSchema: {
|
|
102
|
+
type: 'object',
|
|
103
|
+
properties: {
|
|
104
|
+
bindingIndex: {
|
|
105
|
+
type: 'number',
|
|
106
|
+
description: 'The binding index to inspect',
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
required: ['bindingIndex'],
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
name: 'llui_search_state',
|
|
114
|
+
description: 'Search current state using a dot-separated path query. E.g., "cart.items" returns the items array.',
|
|
115
|
+
inputSchema: {
|
|
116
|
+
type: 'object',
|
|
117
|
+
properties: {
|
|
118
|
+
query: {
|
|
119
|
+
type: 'string',
|
|
120
|
+
description: 'Dot-separated path to search. E.g., "user.name", "items"',
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
required: ['query'],
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
name: 'llui_clear_log',
|
|
128
|
+
description: 'Clear the message and effects history.',
|
|
129
|
+
inputSchema: {
|
|
130
|
+
type: 'object',
|
|
131
|
+
properties: {},
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
name: 'llui_list_messages',
|
|
136
|
+
description: 'List all message variants the component accepts, with their field types. Returns { discriminant, variants: { [name]: { [field]: typeDescriptor } } }. Use this to discover what messages can be sent without reading source code.',
|
|
137
|
+
inputSchema: {
|
|
138
|
+
type: 'object',
|
|
139
|
+
properties: {},
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
name: 'llui_decode_mask',
|
|
144
|
+
description: "Decode a dirty-mask value from llui_get_message_history (the 'dirtyMask' field) into the list of top-level state fields that changed. Requires 'mask' param.",
|
|
145
|
+
inputSchema: {
|
|
146
|
+
type: 'object',
|
|
147
|
+
properties: {
|
|
148
|
+
mask: { type: 'number', description: 'The dirtyMask value to decode' },
|
|
149
|
+
},
|
|
150
|
+
required: ['mask'],
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
name: 'llui_mask_legend',
|
|
155
|
+
description: 'Return the compiler-generated bit→field map for this component. Example: { todos: 1, filter: 2, nextId: 4 } means bit 0 represents `todos`, etc.',
|
|
156
|
+
inputSchema: {
|
|
157
|
+
type: 'object',
|
|
158
|
+
properties: {},
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
name: 'llui_component_info',
|
|
163
|
+
description: 'Get component name and source location (file + line) of the component() declaration. Lets you find where to read or edit the component.',
|
|
164
|
+
inputSchema: {
|
|
165
|
+
type: 'object',
|
|
166
|
+
properties: {},
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
name: 'llui_describe_state',
|
|
171
|
+
description: "Return the State type's shape (not its value). Fields map to type descriptors: 'string', 'number', 'boolean', {kind:'enum',values:[...]}, {kind:'array',of:...}, {kind:'object',fields:...}, {kind:'optional',of:...}. Use this to know what fields exist and their types even when currently undefined.",
|
|
172
|
+
inputSchema: {
|
|
173
|
+
type: 'object',
|
|
174
|
+
properties: {},
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
name: 'llui_list_effects',
|
|
179
|
+
description: 'List all effect variants the component emits, with their field types (same format as llui_list_messages). Returns null if no Effect type is declared.',
|
|
180
|
+
inputSchema: {
|
|
181
|
+
type: 'object',
|
|
182
|
+
properties: {},
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
name: 'llui_trace_element',
|
|
187
|
+
description: "Find all bindings targeting a DOM element matched by a CSS selector. Returns { bindingIndex, kind, key, mask, lastValue, relation }[] so you can answer 'why is this element wrong?' — combine with llui_why_did_update(bindingIndex) for a full narrative.",
|
|
188
|
+
inputSchema: {
|
|
189
|
+
type: 'object',
|
|
190
|
+
properties: {
|
|
191
|
+
selector: { type: 'string', description: 'CSS selector (e.g. `.todo.active`, `#submit`)' },
|
|
192
|
+
},
|
|
193
|
+
required: ['selector'],
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
name: 'llui_snapshot_state',
|
|
198
|
+
description: 'Capture the current state (deep clone). Returns the snapshot — store it, then call llui_restore_state later to roll back. Useful for safely exploring transitions during a debugging session.',
|
|
199
|
+
inputSchema: { type: 'object', properties: {} },
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
name: 'llui_restore_state',
|
|
203
|
+
description: 'Overwrite the current state with a previously-captured snapshot. Triggers a full re-render (FULL_MASK). Bypasses update() — snap must already be a valid state value.',
|
|
204
|
+
inputSchema: {
|
|
205
|
+
type: 'object',
|
|
206
|
+
properties: {
|
|
207
|
+
snapshot: {
|
|
208
|
+
description: 'The state object returned by llui_snapshot_state.',
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
required: ['snapshot'],
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
name: 'llui_list_components',
|
|
216
|
+
description: 'List all currently-mounted LLui components + which one is active (being targeted by subsequent tool calls). Multi-mount apps show one entry per mount.',
|
|
217
|
+
inputSchema: { type: 'object', properties: {} },
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
name: 'llui_select_component',
|
|
221
|
+
description: 'Switch the active component (the one all other tool calls target). Use a key from llui_list_components.',
|
|
222
|
+
inputSchema: {
|
|
223
|
+
type: 'object',
|
|
224
|
+
properties: {
|
|
225
|
+
key: { type: 'string', description: 'Component key as returned by llui_list_components' },
|
|
226
|
+
},
|
|
227
|
+
required: ['key'],
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
name: 'llui_replay_trace',
|
|
232
|
+
description: 'Generate a ready-to-run vitest file that replays the current message history via `replayTrace()` from @llui/test. The output is a complete test file with the trace inlined — paste it into packages/<pkg>/test/ to reproduce the exact sequence of messages the component saw in this session. Use this to capture a debugging session as a regression test.',
|
|
233
|
+
inputSchema: {
|
|
234
|
+
type: 'object',
|
|
235
|
+
properties: {
|
|
236
|
+
importPath: {
|
|
237
|
+
type: 'string',
|
|
238
|
+
description: "Where to import the component def from in the generated test (default: '../src/index'). Example: '../src/todo-app'.",
|
|
239
|
+
},
|
|
240
|
+
exportName: {
|
|
241
|
+
type: 'string',
|
|
242
|
+
description: "Named export that holds the component def (default: the component's name).",
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
},
|
|
247
|
+
];
|
|
248
|
+
export class LluiMcpServer {
|
|
249
|
+
/** Direct (same-process) debug API, used for tests or in-process bridging. */
|
|
250
|
+
debugApi = null;
|
|
251
|
+
/** Bridge (WebSocket) state for out-of-process browser connection. */
|
|
252
|
+
wsServer = null;
|
|
253
|
+
browserWs = null;
|
|
254
|
+
pending = new Map();
|
|
255
|
+
bridgePort;
|
|
256
|
+
constructor(bridgePort = 5200) {
|
|
257
|
+
this.bridgePort = bridgePort;
|
|
258
|
+
}
|
|
259
|
+
/** Connect to a debug API instance directly (for in-process usage). */
|
|
260
|
+
connectDirect(api) {
|
|
261
|
+
this.debugApi = api;
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Start a WebSocket server on the configured bridge port. The browser-side
|
|
265
|
+
* relay (injected by the Vite plugin in dev mode) connects here and forwards
|
|
266
|
+
* debug-API calls.
|
|
267
|
+
*/
|
|
268
|
+
startBridge() {
|
|
269
|
+
if (this.wsServer)
|
|
270
|
+
return;
|
|
271
|
+
this.wsServer = new WebSocketServer({ port: this.bridgePort, host: '127.0.0.1' });
|
|
272
|
+
this.wsServer.on('connection', (ws) => {
|
|
273
|
+
this.browserWs = ws;
|
|
274
|
+
ws.on('message', (raw) => {
|
|
275
|
+
let msg;
|
|
276
|
+
try {
|
|
277
|
+
msg = JSON.parse(String(raw));
|
|
278
|
+
}
|
|
279
|
+
catch {
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
const p = this.pending.get(msg.id);
|
|
283
|
+
if (!p)
|
|
284
|
+
return;
|
|
285
|
+
this.pending.delete(msg.id);
|
|
286
|
+
if (msg.error)
|
|
287
|
+
p.reject(new Error(msg.error));
|
|
288
|
+
else
|
|
289
|
+
p.resolve(msg.result);
|
|
290
|
+
});
|
|
291
|
+
ws.on('close', () => {
|
|
292
|
+
if (this.browserWs === ws)
|
|
293
|
+
this.browserWs = null;
|
|
294
|
+
});
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
stopBridge() {
|
|
298
|
+
this.wsServer?.close();
|
|
299
|
+
this.wsServer = null;
|
|
300
|
+
this.browserWs = null;
|
|
301
|
+
for (const p of this.pending.values())
|
|
302
|
+
p.reject(new Error('bridge closed'));
|
|
303
|
+
this.pending.clear();
|
|
304
|
+
}
|
|
305
|
+
/** Invoke a debug API method — over the bridge if connected, else direct. */
|
|
306
|
+
async call(method, args) {
|
|
307
|
+
if (this.debugApi) {
|
|
308
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
309
|
+
const fn = this.debugApi[method];
|
|
310
|
+
return typeof fn === 'function' ? fn.apply(this.debugApi, args) : undefined;
|
|
311
|
+
}
|
|
312
|
+
if (!this.browserWs) {
|
|
313
|
+
throw new Error('No browser connected to the MCP bridge. Start your dev server.');
|
|
314
|
+
}
|
|
315
|
+
const id = randomUUID();
|
|
316
|
+
return new Promise((resolve, reject) => {
|
|
317
|
+
this.pending.set(id, { resolve, reject });
|
|
318
|
+
this.browserWs.send(JSON.stringify({ id, method, args }));
|
|
319
|
+
setTimeout(() => {
|
|
320
|
+
if (this.pending.delete(id))
|
|
321
|
+
reject(new Error(`timeout: ${method}`));
|
|
322
|
+
}, 5000);
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
/** Get tool definitions for MCP handshake */
|
|
326
|
+
getTools() {
|
|
327
|
+
return TOOLS;
|
|
328
|
+
}
|
|
329
|
+
/** Handle an MCP tool call */
|
|
330
|
+
async handleToolCall(name, args) {
|
|
331
|
+
switch (name) {
|
|
332
|
+
case 'llui_get_state':
|
|
333
|
+
return this.call('getState', []);
|
|
334
|
+
case 'llui_send_message': {
|
|
335
|
+
const errors = (await this.call('validateMessage', [args.msg]));
|
|
336
|
+
if (errors)
|
|
337
|
+
return { errors, sent: false };
|
|
338
|
+
await this.call('send', [args.msg]);
|
|
339
|
+
await this.call('flush', []);
|
|
340
|
+
return { state: await this.call('getState', []), sent: true };
|
|
341
|
+
}
|
|
342
|
+
case 'llui_eval_update':
|
|
343
|
+
return this.call('evalUpdate', [args.msg]);
|
|
344
|
+
case 'llui_validate_message':
|
|
345
|
+
return this.call('validateMessage', [args.msg]);
|
|
346
|
+
case 'llui_get_message_history': {
|
|
347
|
+
const opts = {};
|
|
348
|
+
if (typeof args.since === 'number')
|
|
349
|
+
opts.since = args.since;
|
|
350
|
+
if (typeof args.limit === 'number')
|
|
351
|
+
opts.limit = args.limit;
|
|
352
|
+
return this.call('getMessageHistory', [opts]);
|
|
353
|
+
}
|
|
354
|
+
case 'llui_export_trace':
|
|
355
|
+
return this.call('exportTrace', []);
|
|
356
|
+
case 'llui_get_bindings':
|
|
357
|
+
return this.call('getBindings', []);
|
|
358
|
+
case 'llui_why_did_update':
|
|
359
|
+
return this.call('whyDidUpdate', [args.bindingIndex]);
|
|
360
|
+
case 'llui_search_state':
|
|
361
|
+
return this.call('searchState', [args.query]);
|
|
362
|
+
case 'llui_clear_log':
|
|
363
|
+
await this.call('clearLog', []);
|
|
364
|
+
return { cleared: true };
|
|
365
|
+
case 'llui_list_messages':
|
|
366
|
+
return this.call('getMessageSchema', []);
|
|
367
|
+
case 'llui_decode_mask':
|
|
368
|
+
return this.call('decodeMask', [args.mask]);
|
|
369
|
+
case 'llui_mask_legend':
|
|
370
|
+
return this.call('getMaskLegend', []);
|
|
371
|
+
case 'llui_component_info':
|
|
372
|
+
return this.call('getComponentInfo', []);
|
|
373
|
+
case 'llui_describe_state':
|
|
374
|
+
return this.call('getStateSchema', []);
|
|
375
|
+
case 'llui_list_effects':
|
|
376
|
+
return this.call('getEffectSchema', []);
|
|
377
|
+
case 'llui_trace_element':
|
|
378
|
+
return this.call('getBindingsFor', [args.selector]);
|
|
379
|
+
case 'llui_snapshot_state':
|
|
380
|
+
return this.call('snapshotState', []);
|
|
381
|
+
case 'llui_restore_state':
|
|
382
|
+
await this.call('restoreState', [args.snapshot]);
|
|
383
|
+
return { restored: true, state: await this.call('getState', []) };
|
|
384
|
+
case 'llui_list_components':
|
|
385
|
+
return this.call('__listComponents', []);
|
|
386
|
+
case 'llui_select_component':
|
|
387
|
+
return this.call('__selectComponent', [args.key]);
|
|
388
|
+
case 'llui_replay_trace': {
|
|
389
|
+
const trace = (await this.call('exportTrace', []));
|
|
390
|
+
const importPath = args.importPath ?? '../src/index';
|
|
391
|
+
const exportName = args.exportName ?? trace.component;
|
|
392
|
+
return {
|
|
393
|
+
filename: `${trace.component.toLowerCase()}-replay.test.ts`,
|
|
394
|
+
code: generateReplayTest(trace, importPath, exportName),
|
|
395
|
+
entryCount: trace.entries.length,
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
default:
|
|
399
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
/** Start the MCP server on stdin/stdout */
|
|
403
|
+
start() {
|
|
404
|
+
let buffer = '';
|
|
405
|
+
process.stdin.setEncoding('utf8');
|
|
406
|
+
process.stdin.on('data', (chunk) => {
|
|
407
|
+
buffer += chunk;
|
|
408
|
+
// MCP uses newline-delimited JSON
|
|
409
|
+
const lines = buffer.split('\n');
|
|
410
|
+
buffer = lines.pop(); // keep incomplete line
|
|
411
|
+
for (const line of lines) {
|
|
412
|
+
if (!line.trim())
|
|
413
|
+
continue;
|
|
414
|
+
try {
|
|
415
|
+
const request = JSON.parse(line);
|
|
416
|
+
this.handleRequest(request).then((response) => {
|
|
417
|
+
process.stdout.write(JSON.stringify(response) + '\n');
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
catch {
|
|
421
|
+
// Ignore parse errors
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
async handleRequest(request) {
|
|
427
|
+
try {
|
|
428
|
+
switch (request.method) {
|
|
429
|
+
case 'initialize':
|
|
430
|
+
return {
|
|
431
|
+
jsonrpc: '2.0',
|
|
432
|
+
id: request.id,
|
|
433
|
+
result: {
|
|
434
|
+
protocolVersion: '2024-11-05',
|
|
435
|
+
capabilities: { tools: {} },
|
|
436
|
+
serverInfo: { name: '@llui/mcp', version: '0.0.0' },
|
|
437
|
+
},
|
|
438
|
+
};
|
|
439
|
+
case 'tools/list':
|
|
440
|
+
return {
|
|
441
|
+
jsonrpc: '2.0',
|
|
442
|
+
id: request.id,
|
|
443
|
+
result: { tools: this.getTools() },
|
|
444
|
+
};
|
|
445
|
+
case 'tools/call': {
|
|
446
|
+
const params = request.params;
|
|
447
|
+
const result = await this.handleToolCall(params.name, params.arguments ?? {});
|
|
448
|
+
return {
|
|
449
|
+
jsonrpc: '2.0',
|
|
450
|
+
id: request.id,
|
|
451
|
+
result: {
|
|
452
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
453
|
+
},
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
default:
|
|
457
|
+
return {
|
|
458
|
+
jsonrpc: '2.0',
|
|
459
|
+
id: request.id,
|
|
460
|
+
error: {
|
|
461
|
+
code: -32601,
|
|
462
|
+
message: `Method not found: ${request.method}`,
|
|
463
|
+
},
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
catch (err) {
|
|
468
|
+
return {
|
|
469
|
+
jsonrpc: '2.0',
|
|
470
|
+
id: request.id,
|
|
471
|
+
error: { code: -32000, message: String(err) },
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
export { TOOLS as mcpToolDefinitions };
|
|
477
|
+
function generateReplayTest(trace, importPath, exportName) {
|
|
478
|
+
const traceJson = JSON.stringify({
|
|
479
|
+
lluiTrace: 1,
|
|
480
|
+
component: trace.component,
|
|
481
|
+
generatedBy: 'llui-mcp',
|
|
482
|
+
timestamp: new Date().toISOString(),
|
|
483
|
+
entries: trace.entries,
|
|
484
|
+
}, null, 2);
|
|
485
|
+
return `import { it, expect } from 'vitest'
|
|
486
|
+
import { replayTrace } from '@llui/test'
|
|
487
|
+
import { ${exportName} } from '${importPath}'
|
|
488
|
+
|
|
489
|
+
// Auto-generated from a debugging session via llui_replay_trace MCP tool.
|
|
490
|
+
// Edit the trace below to trim, reorder, or adjust expected state/effects.
|
|
491
|
+
const trace = ${traceJson} as const
|
|
492
|
+
|
|
493
|
+
it('${trace.component}: replays ${trace.entries.length} recorded message${trace.entries.length === 1 ? '' : 's'}', () => {
|
|
494
|
+
expect(() => replayTrace(${exportName}, trace as Parameters<typeof replayTrace>[1])).not.toThrow()
|
|
495
|
+
})
|
|
496
|
+
`;
|
|
497
|
+
}
|
|
498
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@llui/mcp",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"sideEffects": false,
|
|
6
|
+
"bin": {
|
|
7
|
+
"llui-mcp": "./dist/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsc -p tsconfig.build.json",
|
|
20
|
+
"check": "tsc --noEmit",
|
|
21
|
+
"lint": "eslint src",
|
|
22
|
+
"test": "vitest run"
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@llui/dom": "workspace:*",
|
|
26
|
+
"ws": "^8.18.0"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@types/node": "^22.0.0",
|
|
30
|
+
"@types/ws": "^8.5.13"
|
|
31
|
+
},
|
|
32
|
+
"description": "LLui MCP server — LLM debug tools via Model Context Protocol",
|
|
33
|
+
"keywords": [
|
|
34
|
+
"llui",
|
|
35
|
+
"mcp",
|
|
36
|
+
"debug",
|
|
37
|
+
"llm",
|
|
38
|
+
"devtools"
|
|
39
|
+
],
|
|
40
|
+
"author": "Franco Ponticelli <franco.ponticelli@gmail.com>",
|
|
41
|
+
"license": "MIT",
|
|
42
|
+
"repository": {
|
|
43
|
+
"type": "git",
|
|
44
|
+
"url": "git+https://github.com/fponticelli/llui.git",
|
|
45
|
+
"directory": "packages/mcp"
|
|
46
|
+
},
|
|
47
|
+
"bugs": {
|
|
48
|
+
"url": "https://github.com/fponticelli/llui/issues"
|
|
49
|
+
},
|
|
50
|
+
"homepage": "https://github.com/fponticelli/llui/tree/main/packages/mcp#readme"
|
|
51
|
+
}
|