rsbuild-plugin-vue-mcp 0.1.1 → 0.1.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 +2 -1
- package/README_zh.md +2 -1
- package/dist/396.js +237 -0
- package/dist/index.cjs +112 -214
- package/dist/index.js +2 -4
- package/dist/overlay-bootstrap.js +1 -1
- package/dist/overlay.js +24 -12
- package/dist/rspack.cjs +112 -214
- package/dist/rspack.js +2 -4
- package/dist/types/types.d.ts +6 -24
- package/package.json +1 -3
- package/dist/551.js +0 -337
- package/dist/types/mcp/rpc.d.ts +0 -2
package/README.md
CHANGED
|
@@ -104,9 +104,10 @@ Add that URL to your client's MCP configuration (Cursor, Claude Desktop, VS Code
|
|
|
104
104
|
```json
|
|
105
105
|
{
|
|
106
106
|
"mcpServers": {
|
|
107
|
-
"vue-
|
|
107
|
+
"vue-devtools": {
|
|
108
108
|
"type": "streamable-http",
|
|
109
109
|
"url": "http://localhost:<YourPort>/__mcp/mcp",
|
|
110
|
+
"description": "Vue DevTools MCP - Rsbuild/Rspack MCP plugin based on Vue DevTools",
|
|
110
111
|
"disabled": false
|
|
111
112
|
}
|
|
112
113
|
}
|
package/README_zh.md
CHANGED
|
@@ -101,9 +101,10 @@ MCP 服务(基于 Streamable HTTP 传输)将在 `http://localhost:[port]/__m
|
|
|
101
101
|
```json
|
|
102
102
|
{
|
|
103
103
|
"mcpServers": {
|
|
104
|
-
"vue-
|
|
104
|
+
"vue-devtools": {
|
|
105
105
|
"type": "streamable-http",
|
|
106
106
|
"url": "http://localhost:<YourPort>/__mcp/mcp",
|
|
107
|
+
"description": "Vue DevTools MCP - Rsbuild/Rspack MCP plugin based on Vue DevTools",
|
|
107
108
|
"disabled": false
|
|
108
109
|
}
|
|
109
110
|
}
|
package/dist/396.js
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import { createBirpcGroup } from "birpc";
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
5
|
+
function createVueMcpContext() {
|
|
6
|
+
return {
|
|
7
|
+
rpcServer: null
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
const channelCache = new WeakMap();
|
|
11
|
+
function createRPCServer(ws, functions, options = {}) {
|
|
12
|
+
const group = createBirpcGroup(functions, ()=>Array.from(ws?.clients || []).map((channel)=>{
|
|
13
|
+
if (channel.readyState === channel.CLOSED) return;
|
|
14
|
+
const cached = channelCache.get(channel);
|
|
15
|
+
if (cached) return cached;
|
|
16
|
+
const options = {
|
|
17
|
+
on: (fn)=>channel.on('message', fn),
|
|
18
|
+
post: (data)=>channel.send(data),
|
|
19
|
+
serialize: (v)=>JSON.stringify(v),
|
|
20
|
+
deserialize: (v)=>JSON.parse(v)
|
|
21
|
+
};
|
|
22
|
+
channelCache.set(channel, options);
|
|
23
|
+
return options;
|
|
24
|
+
}).filter((c)=>!!c), options);
|
|
25
|
+
ws.on('connection', ()=>{
|
|
26
|
+
group.updateChannels();
|
|
27
|
+
});
|
|
28
|
+
return group.broadcast;
|
|
29
|
+
}
|
|
30
|
+
var package_namespaceObject = {
|
|
31
|
+
rE: "0.1.2"
|
|
32
|
+
};
|
|
33
|
+
function stringify(value) {
|
|
34
|
+
return "string" == typeof value ? value : JSON.stringify(value);
|
|
35
|
+
}
|
|
36
|
+
function createMcpServerDefault(options, ctx) {
|
|
37
|
+
const server = new McpServer({
|
|
38
|
+
name: "rsbuild-vue-mcp",
|
|
39
|
+
description: 'Rsbuild/Rspack MCP plugin based on Vue DevTools',
|
|
40
|
+
version: package_namespaceObject.rE,
|
|
41
|
+
...options.mcpServerInfo
|
|
42
|
+
});
|
|
43
|
+
server.registerTool('get-app-record-status', {
|
|
44
|
+
title: 'App Record Status',
|
|
45
|
+
description: "Get the current Devtools App status (appRecords and activeAppRecord). Must be called first before any other MCP tools. An empty content response usually means the user needs to open a web page with an app to debug. If multiple content items are returned, the user has multiple app pages open and should close all but one to avoid interference. If a content contains multiple appRecords, it means multiple Vue App instances exist on the page. `toggle-app` to switch activeAppRecord. "
|
|
46
|
+
}, async ()=>{
|
|
47
|
+
const res = await ctx.rpcServer.getAppRecordStatus();
|
|
48
|
+
return {
|
|
49
|
+
content: res.map((r)=>({
|
|
50
|
+
type: 'text',
|
|
51
|
+
text: stringify(r)
|
|
52
|
+
}))
|
|
53
|
+
};
|
|
54
|
+
});
|
|
55
|
+
server.registerTool('toggle-app', {
|
|
56
|
+
title: 'Toggle App',
|
|
57
|
+
description: 'Toggle the activeAppRecord by the id of the appRecord. All MCP tool operations on Components, Router, Pinia, etc. are performed based on the activeAppRecord.',
|
|
58
|
+
inputSchema: {
|
|
59
|
+
id: z.string()
|
|
60
|
+
}
|
|
61
|
+
}, async ({ id })=>{
|
|
62
|
+
await ctx.rpcServer.toggleApp({
|
|
63
|
+
id
|
|
64
|
+
});
|
|
65
|
+
return {
|
|
66
|
+
content: [
|
|
67
|
+
{
|
|
68
|
+
type: 'text',
|
|
69
|
+
text: 'ok'
|
|
70
|
+
}
|
|
71
|
+
]
|
|
72
|
+
};
|
|
73
|
+
});
|
|
74
|
+
server.registerTool('get-component-tree', {
|
|
75
|
+
description: 'Get the Vue component tree in JSON tree syntax format (by Vue DevTools stringify, a two-dimensional serialization format that separates structure from values, replacing nested object references with IDs.).',
|
|
76
|
+
inputSchema: {
|
|
77
|
+
componentName: z.string().optional().describe('query by componentName (the component\'s name, not uid), default query all components')
|
|
78
|
+
}
|
|
79
|
+
}, async ({ componentName })=>{
|
|
80
|
+
const res = await ctx.rpcServer.getInspectorTree({
|
|
81
|
+
componentName
|
|
82
|
+
});
|
|
83
|
+
return {
|
|
84
|
+
content: res.map((r)=>({
|
|
85
|
+
type: 'text',
|
|
86
|
+
text: stringify(r)
|
|
87
|
+
}))
|
|
88
|
+
};
|
|
89
|
+
});
|
|
90
|
+
server.registerTool('get-component-state', {
|
|
91
|
+
description: 'Get the Vue component state in JSON structure format.',
|
|
92
|
+
inputSchema: {
|
|
93
|
+
componentName: z.string().describe('query by componentName (the component\'s name, not uid)')
|
|
94
|
+
}
|
|
95
|
+
}, async ({ componentName })=>{
|
|
96
|
+
const res = await ctx.rpcServer.getInspectorState({
|
|
97
|
+
componentName
|
|
98
|
+
});
|
|
99
|
+
return {
|
|
100
|
+
content: res.map((r)=>({
|
|
101
|
+
type: 'text',
|
|
102
|
+
text: stringify(r)
|
|
103
|
+
}))
|
|
104
|
+
};
|
|
105
|
+
});
|
|
106
|
+
server.registerTool('edit-component-state', {
|
|
107
|
+
description: 'Edit the Vue component state.',
|
|
108
|
+
inputSchema: {
|
|
109
|
+
componentName: z.string().describe('by componentName (the component\'s name, not uid)'),
|
|
110
|
+
path: z.array(z.string()),
|
|
111
|
+
value: z.string(),
|
|
112
|
+
valueType: z["enum"]([
|
|
113
|
+
'string',
|
|
114
|
+
'number',
|
|
115
|
+
'boolean',
|
|
116
|
+
'object',
|
|
117
|
+
'array'
|
|
118
|
+
])
|
|
119
|
+
}
|
|
120
|
+
}, async ({ componentName, path, value, valueType })=>{
|
|
121
|
+
await ctx.rpcServer.editComponentState({
|
|
122
|
+
componentName,
|
|
123
|
+
path,
|
|
124
|
+
value,
|
|
125
|
+
valueType
|
|
126
|
+
});
|
|
127
|
+
return {
|
|
128
|
+
content: [
|
|
129
|
+
{
|
|
130
|
+
type: 'text',
|
|
131
|
+
text: 'ok'
|
|
132
|
+
}
|
|
133
|
+
]
|
|
134
|
+
};
|
|
135
|
+
});
|
|
136
|
+
server.registerTool('highlight-component', {
|
|
137
|
+
description: 'Highlight the Vue component.',
|
|
138
|
+
inputSchema: {
|
|
139
|
+
componentName: z.string().describe('by componentName (the component\'s name, not uid)')
|
|
140
|
+
}
|
|
141
|
+
}, async ({ componentName })=>{
|
|
142
|
+
await ctx.rpcServer.highlightComponent({
|
|
143
|
+
componentName
|
|
144
|
+
});
|
|
145
|
+
return {
|
|
146
|
+
content: [
|
|
147
|
+
{
|
|
148
|
+
type: 'text',
|
|
149
|
+
text: 'ok'
|
|
150
|
+
}
|
|
151
|
+
]
|
|
152
|
+
};
|
|
153
|
+
});
|
|
154
|
+
server.registerTool('get-router-info', {
|
|
155
|
+
description: 'Get the Vue router info in JSON structure format.'
|
|
156
|
+
}, async ()=>{
|
|
157
|
+
const res = await ctx.rpcServer.getRouterInfo();
|
|
158
|
+
return {
|
|
159
|
+
content: res.map((r)=>({
|
|
160
|
+
type: 'text',
|
|
161
|
+
text: stringify(r)
|
|
162
|
+
}))
|
|
163
|
+
};
|
|
164
|
+
});
|
|
165
|
+
server.registerTool('get-pinia-state', {
|
|
166
|
+
description: 'Get the Pinia state in JSON structure format.',
|
|
167
|
+
inputSchema: {
|
|
168
|
+
storeName: z.string()
|
|
169
|
+
}
|
|
170
|
+
}, async ({ storeName })=>{
|
|
171
|
+
const res = await ctx.rpcServer.getPiniaState({
|
|
172
|
+
storeName
|
|
173
|
+
});
|
|
174
|
+
return {
|
|
175
|
+
content: res.map((r)=>({
|
|
176
|
+
type: 'text',
|
|
177
|
+
text: stringify(r)
|
|
178
|
+
}))
|
|
179
|
+
};
|
|
180
|
+
});
|
|
181
|
+
server.registerTool('get-pinia-tree', {
|
|
182
|
+
description: 'Get the Pinia tree in JSON structure format.'
|
|
183
|
+
}, async ()=>{
|
|
184
|
+
const res = await ctx.rpcServer.getPiniaTree();
|
|
185
|
+
return {
|
|
186
|
+
content: res.map((r)=>({
|
|
187
|
+
type: 'text',
|
|
188
|
+
text: stringify(r)
|
|
189
|
+
}))
|
|
190
|
+
};
|
|
191
|
+
});
|
|
192
|
+
return server;
|
|
193
|
+
}
|
|
194
|
+
async function mcpHandlerStateless(server, req, res) {
|
|
195
|
+
try {
|
|
196
|
+
const transport = new StreamableHTTPServerTransport({
|
|
197
|
+
sessionIdGenerator: void 0
|
|
198
|
+
});
|
|
199
|
+
await server.connect(transport);
|
|
200
|
+
await transport.handleRequest(req, res);
|
|
201
|
+
res.on('close', ()=>{
|
|
202
|
+
transport.close();
|
|
203
|
+
server.close();
|
|
204
|
+
});
|
|
205
|
+
} catch (error) {
|
|
206
|
+
console.error('Error handling MCP request:', error);
|
|
207
|
+
if (!res.headersSent) {
|
|
208
|
+
res.statusCode = 500;
|
|
209
|
+
res.setHeader('content-type', 'application/json');
|
|
210
|
+
res.end(JSON.stringify({
|
|
211
|
+
jsonrpc: '2.0',
|
|
212
|
+
error: {
|
|
213
|
+
code: -32603,
|
|
214
|
+
message: 'Internal server error'
|
|
215
|
+
},
|
|
216
|
+
id: null
|
|
217
|
+
}));
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
function setupRoutes(base, getServer, dev) {
|
|
222
|
+
dev.middlewares.use(`${base}/mcp`, async (req, res)=>{
|
|
223
|
+
const server = await getServer();
|
|
224
|
+
await mcpHandlerStateless(server, req, res);
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
function setupRspackRoutes(base, getServer, middlewares) {
|
|
228
|
+
middlewares.push({
|
|
229
|
+
name: 'vue-devtools-mcp',
|
|
230
|
+
path: `${base}/mcp`,
|
|
231
|
+
async middleware (req, res) {
|
|
232
|
+
const server = await getServer();
|
|
233
|
+
await mcpHandlerStateless(server, req, res);
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
export { createMcpServerDefault, createRPCServer, createVueMcpContext, setupRoutes, setupRspackRoutes };
|
package/dist/index.cjs
CHANGED
|
@@ -48,45 +48,11 @@ var external_node_path_default = /*#__PURE__*/ __webpack_require__.n(external_no
|
|
|
48
48
|
const promises_namespaceObject = require("node:fs/promises");
|
|
49
49
|
var promises_default = /*#__PURE__*/ __webpack_require__.n(promises_namespaceObject);
|
|
50
50
|
const external_ws_namespaceObject = require("ws");
|
|
51
|
-
const external_hookable_namespaceObject = require("hookable");
|
|
52
51
|
function createVueMcpContext() {
|
|
53
52
|
return {
|
|
54
|
-
hooks: (0, external_hookable_namespaceObject.createHooks)(),
|
|
55
|
-
rpc: null,
|
|
56
53
|
rpcServer: null
|
|
57
54
|
};
|
|
58
55
|
}
|
|
59
|
-
function createServerRpcFunc(ctx) {
|
|
60
|
-
return {
|
|
61
|
-
getAppRecordStatus: (_)=>({}),
|
|
62
|
-
onAppRecordStatusUpdate: (event, data)=>{
|
|
63
|
-
ctx.hooks.callHook(event, data).finally();
|
|
64
|
-
},
|
|
65
|
-
toggleApp: (_)=>({}),
|
|
66
|
-
getInspectorTree: (_)=>({}),
|
|
67
|
-
onInspectorTreeUpdated: (event, data)=>{
|
|
68
|
-
ctx.hooks.callHook(event, data).finally();
|
|
69
|
-
},
|
|
70
|
-
getInspectorState: (_)=>({}),
|
|
71
|
-
onInspectorStateUpdated: (event, data)=>{
|
|
72
|
-
ctx.hooks.callHook(event, data).finally();
|
|
73
|
-
},
|
|
74
|
-
editComponentState (_) {},
|
|
75
|
-
highlightComponent (_) {},
|
|
76
|
-
getRouterInfo: (_)=>({}),
|
|
77
|
-
onRouterInfoUpdated: (event, data)=>{
|
|
78
|
-
ctx.hooks.callHook(event, data).finally();
|
|
79
|
-
},
|
|
80
|
-
getPiniaTree: (_)=>({}),
|
|
81
|
-
onPiniaTreeUpdated: (event, data)=>{
|
|
82
|
-
ctx.hooks.callHook(event, data).finally();
|
|
83
|
-
},
|
|
84
|
-
getPiniaState: (_)=>({}),
|
|
85
|
-
onPiniaInfoUpdated: (event, data)=>{
|
|
86
|
-
ctx.hooks.callHook(event, data).finally();
|
|
87
|
-
}
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
56
|
const external_birpc_namespaceObject = require("birpc");
|
|
91
57
|
const channelCache = new WeakMap();
|
|
92
58
|
function createRPCServer(ws, functions, options = {}) {
|
|
@@ -110,9 +76,8 @@ function createRPCServer(ws, functions, options = {}) {
|
|
|
110
76
|
}
|
|
111
77
|
const mcp_js_namespaceObject = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
112
78
|
var package_namespaceObject = {
|
|
113
|
-
rE: "0.1.
|
|
79
|
+
rE: "0.1.2"
|
|
114
80
|
};
|
|
115
|
-
const external_nanoid_namespaceObject = require("nanoid");
|
|
116
81
|
const external_zod_namespaceObject = require("zod");
|
|
117
82
|
function stringify(value) {
|
|
118
83
|
return "string" == typeof value ? value : JSON.stringify(value);
|
|
@@ -126,99 +91,71 @@ function createMcpServerDefault(options, ctx) {
|
|
|
126
91
|
});
|
|
127
92
|
server.registerTool('get-app-record-status', {
|
|
128
93
|
title: 'App Record Status',
|
|
129
|
-
description:
|
|
130
|
-
}, async ()=>
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
]
|
|
140
|
-
});
|
|
141
|
-
});
|
|
142
|
-
ctx.rpcServer.getAppRecordStatus({
|
|
143
|
-
event: eventName
|
|
144
|
-
}).catch((e)=>{
|
|
145
|
-
console.error(e);
|
|
146
|
-
reject(e);
|
|
147
|
-
});
|
|
148
|
-
}));
|
|
94
|
+
description: "Get the current Devtools App status (appRecords and activeAppRecord). Must be called first before any other MCP tools. An empty content response usually means the user needs to open a web page with an app to debug. If multiple content items are returned, the user has multiple app pages open and should close all but one to avoid interference. If a content contains multiple appRecords, it means multiple Vue App instances exist on the page. `toggle-app` to switch activeAppRecord. "
|
|
95
|
+
}, async ()=>{
|
|
96
|
+
const res = await ctx.rpcServer.getAppRecordStatus();
|
|
97
|
+
return {
|
|
98
|
+
content: res.map((r)=>({
|
|
99
|
+
type: 'text',
|
|
100
|
+
text: stringify(r)
|
|
101
|
+
}))
|
|
102
|
+
};
|
|
103
|
+
});
|
|
149
104
|
server.registerTool('toggle-app', {
|
|
150
105
|
title: 'Toggle App',
|
|
151
106
|
description: 'Toggle the activeAppRecord by the id of the appRecord. All MCP tool operations on Components, Router, Pinia, etc. are performed based on the activeAppRecord.',
|
|
152
107
|
inputSchema: {
|
|
153
108
|
id: external_zod_namespaceObject.z.string()
|
|
154
109
|
}
|
|
155
|
-
}, async ({ id })=>
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
console.error(e);
|
|
169
|
-
reject(e);
|
|
170
|
-
});
|
|
171
|
-
}));
|
|
110
|
+
}, async ({ id })=>{
|
|
111
|
+
await ctx.rpcServer.toggleApp({
|
|
112
|
+
id
|
|
113
|
+
});
|
|
114
|
+
return {
|
|
115
|
+
content: [
|
|
116
|
+
{
|
|
117
|
+
type: 'text',
|
|
118
|
+
text: 'ok'
|
|
119
|
+
}
|
|
120
|
+
]
|
|
121
|
+
};
|
|
122
|
+
});
|
|
172
123
|
server.registerTool('get-component-tree', {
|
|
173
|
-
description: 'Get the Vue component tree in JSON tree syntax format (by Vue DevTools stringify, a two-dimensional serialization format that separates structure from values, replacing nested object references with IDs.).'
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
}).catch((e)=>{
|
|
189
|
-
console.error(e);
|
|
190
|
-
reject(e);
|
|
191
|
-
});
|
|
192
|
-
}));
|
|
124
|
+
description: 'Get the Vue component tree in JSON tree syntax format (by Vue DevTools stringify, a two-dimensional serialization format that separates structure from values, replacing nested object references with IDs.).',
|
|
125
|
+
inputSchema: {
|
|
126
|
+
componentName: external_zod_namespaceObject.z.string().optional().describe('query by componentName (the component\'s name, not uid), default query all components')
|
|
127
|
+
}
|
|
128
|
+
}, async ({ componentName })=>{
|
|
129
|
+
const res = await ctx.rpcServer.getInspectorTree({
|
|
130
|
+
componentName
|
|
131
|
+
});
|
|
132
|
+
return {
|
|
133
|
+
content: res.map((r)=>({
|
|
134
|
+
type: 'text',
|
|
135
|
+
text: stringify(r)
|
|
136
|
+
}))
|
|
137
|
+
};
|
|
138
|
+
});
|
|
193
139
|
server.registerTool('get-component-state', {
|
|
194
140
|
description: 'Get the Vue component state in JSON structure format.',
|
|
195
141
|
inputSchema: {
|
|
196
|
-
componentName: external_zod_namespaceObject.z.string()
|
|
142
|
+
componentName: external_zod_namespaceObject.z.string().describe('query by componentName (the component\'s name, not uid)')
|
|
197
143
|
}
|
|
198
|
-
}, async ({ componentName })=>
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
});
|
|
210
|
-
ctx.rpcServer.getInspectorState({
|
|
211
|
-
event: eventName,
|
|
212
|
-
componentName
|
|
213
|
-
}).catch((e)=>{
|
|
214
|
-
console.error(e);
|
|
215
|
-
reject(e);
|
|
216
|
-
});
|
|
217
|
-
}));
|
|
144
|
+
}, async ({ componentName })=>{
|
|
145
|
+
const res = await ctx.rpcServer.getInspectorState({
|
|
146
|
+
componentName
|
|
147
|
+
});
|
|
148
|
+
return {
|
|
149
|
+
content: res.map((r)=>({
|
|
150
|
+
type: 'text',
|
|
151
|
+
text: stringify(r)
|
|
152
|
+
}))
|
|
153
|
+
};
|
|
154
|
+
});
|
|
218
155
|
server.registerTool('edit-component-state', {
|
|
219
156
|
description: 'Edit the Vue component state.',
|
|
220
157
|
inputSchema: {
|
|
221
|
-
componentName: external_zod_namespaceObject.z.string(),
|
|
158
|
+
componentName: external_zod_namespaceObject.z.string().describe('by componentName (the component\'s name, not uid)'),
|
|
222
159
|
path: external_zod_namespaceObject.z.array(external_zod_namespaceObject.z.string()),
|
|
223
160
|
value: external_zod_namespaceObject.z.string(),
|
|
224
161
|
valueType: external_zod_namespaceObject.z["enum"]([
|
|
@@ -229,115 +166,78 @@ function createMcpServerDefault(options, ctx) {
|
|
|
229
166
|
'array'
|
|
230
167
|
])
|
|
231
168
|
}
|
|
232
|
-
}, async ({ componentName, path, value, valueType })=>
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
console.error(e);
|
|
249
|
-
reject(e);
|
|
250
|
-
});
|
|
251
|
-
}));
|
|
169
|
+
}, async ({ componentName, path, value, valueType })=>{
|
|
170
|
+
await ctx.rpcServer.editComponentState({
|
|
171
|
+
componentName,
|
|
172
|
+
path,
|
|
173
|
+
value,
|
|
174
|
+
valueType
|
|
175
|
+
});
|
|
176
|
+
return {
|
|
177
|
+
content: [
|
|
178
|
+
{
|
|
179
|
+
type: 'text',
|
|
180
|
+
text: 'ok'
|
|
181
|
+
}
|
|
182
|
+
]
|
|
183
|
+
};
|
|
184
|
+
});
|
|
252
185
|
server.registerTool('highlight-component', {
|
|
253
186
|
description: 'Highlight the Vue component.',
|
|
254
187
|
inputSchema: {
|
|
255
|
-
componentName: external_zod_namespaceObject.z.string()
|
|
188
|
+
componentName: external_zod_namespaceObject.z.string().describe('by componentName (the component\'s name, not uid)')
|
|
256
189
|
}
|
|
257
|
-
}, async ({ componentName })=>
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
console.error(e);
|
|
271
|
-
reject(e);
|
|
272
|
-
});
|
|
273
|
-
}));
|
|
190
|
+
}, async ({ componentName })=>{
|
|
191
|
+
await ctx.rpcServer.highlightComponent({
|
|
192
|
+
componentName
|
|
193
|
+
});
|
|
194
|
+
return {
|
|
195
|
+
content: [
|
|
196
|
+
{
|
|
197
|
+
type: 'text',
|
|
198
|
+
text: 'ok'
|
|
199
|
+
}
|
|
200
|
+
]
|
|
201
|
+
};
|
|
202
|
+
});
|
|
274
203
|
server.registerTool('get-router-info', {
|
|
275
204
|
description: 'Get the Vue router info in JSON structure format.'
|
|
276
|
-
}, async ()=>
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
]
|
|
286
|
-
});
|
|
287
|
-
});
|
|
288
|
-
ctx.rpcServer.getRouterInfo({
|
|
289
|
-
event: eventName
|
|
290
|
-
}).catch((e)=>{
|
|
291
|
-
console.error(e);
|
|
292
|
-
reject(e);
|
|
293
|
-
});
|
|
294
|
-
}));
|
|
205
|
+
}, async ()=>{
|
|
206
|
+
const res = await ctx.rpcServer.getRouterInfo();
|
|
207
|
+
return {
|
|
208
|
+
content: res.map((r)=>({
|
|
209
|
+
type: 'text',
|
|
210
|
+
text: stringify(r)
|
|
211
|
+
}))
|
|
212
|
+
};
|
|
213
|
+
});
|
|
295
214
|
server.registerTool('get-pinia-state', {
|
|
296
215
|
description: 'Get the Pinia state in JSON structure format.',
|
|
297
216
|
inputSchema: {
|
|
298
217
|
storeName: external_zod_namespaceObject.z.string()
|
|
299
218
|
}
|
|
300
|
-
}, async ({ storeName })=>
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
});
|
|
312
|
-
ctx.rpcServer.getPiniaState({
|
|
313
|
-
event: eventName,
|
|
314
|
-
storeName
|
|
315
|
-
}).catch((e)=>{
|
|
316
|
-
console.error(e);
|
|
317
|
-
reject(e);
|
|
318
|
-
});
|
|
319
|
-
}));
|
|
219
|
+
}, async ({ storeName })=>{
|
|
220
|
+
const res = await ctx.rpcServer.getPiniaState({
|
|
221
|
+
storeName
|
|
222
|
+
});
|
|
223
|
+
return {
|
|
224
|
+
content: res.map((r)=>({
|
|
225
|
+
type: 'text',
|
|
226
|
+
text: stringify(r)
|
|
227
|
+
}))
|
|
228
|
+
};
|
|
229
|
+
});
|
|
320
230
|
server.registerTool('get-pinia-tree', {
|
|
321
231
|
description: 'Get the Pinia tree in JSON structure format.'
|
|
322
|
-
}, async ()=>
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
]
|
|
332
|
-
});
|
|
333
|
-
});
|
|
334
|
-
ctx.rpcServer.getPiniaTree({
|
|
335
|
-
event: eventName
|
|
336
|
-
}).catch((e)=>{
|
|
337
|
-
console.error(e);
|
|
338
|
-
reject(e);
|
|
339
|
-
});
|
|
340
|
-
}));
|
|
232
|
+
}, async ()=>{
|
|
233
|
+
const res = await ctx.rpcServer.getPiniaTree();
|
|
234
|
+
return {
|
|
235
|
+
content: res.map((r)=>({
|
|
236
|
+
type: 'text',
|
|
237
|
+
text: stringify(r)
|
|
238
|
+
}))
|
|
239
|
+
};
|
|
240
|
+
});
|
|
341
241
|
return server;
|
|
342
242
|
}
|
|
343
243
|
const streamableHttp_js_namespaceObject = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
|
|
@@ -448,11 +348,9 @@ const pluginVueMcp = (options = {})=>({
|
|
|
448
348
|
wss.emit('connection', client, request);
|
|
449
349
|
});
|
|
450
350
|
});
|
|
451
|
-
|
|
452
|
-
ctx.rpcServer = createRPCServer(wss, rpc, {
|
|
351
|
+
ctx.rpcServer = createRPCServer(wss, {}, {
|
|
453
352
|
timeout: 3000
|
|
454
353
|
});
|
|
455
|
-
ctx.rpc = rpc;
|
|
456
354
|
const { printUrl = true, mcpPath = '/__mcp' } = options;
|
|
457
355
|
setupRoutes(mcpPath, async ()=>{
|
|
458
356
|
let mcp = createMcpServerDefault(options, ctx);
|