@xiaou66/vite-plugin-vue-mcp-next 0.0.1 → 0.0.3
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 +18 -15
- package/dist/index.cjs +58 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +58 -18
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -28,33 +28,34 @@ pnpm add -D @xiaou66/vite-plugin-vue-mcp-next
|
|
|
28
28
|
```ts
|
|
29
29
|
import vue from '@vitejs/plugin-vue'
|
|
30
30
|
import { defineConfig } from 'vite'
|
|
31
|
-
import vueMcpNext from 'vite-plugin-vue-mcp-next'
|
|
31
|
+
import vueMcpNext from '@xiaou66/vite-plugin-vue-mcp-next'
|
|
32
32
|
|
|
33
33
|
export default defineConfig({
|
|
34
34
|
plugins: [vue(), vueMcpNext()]
|
|
35
35
|
})
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
-
启动 Vite
|
|
38
|
+
启动 Vite 后,默认会暴露两个 MCP 入口:
|
|
39
39
|
|
|
40
40
|
```text
|
|
41
|
-
http://localhost:<vite-port>/__mcp/sse
|
|
41
|
+
SSE: http://localhost:<vite-port>/__mcp/sse
|
|
42
|
+
Streamable HTTP: http://localhost:<vite-port>/__mcp/mcp
|
|
42
43
|
```
|
|
43
44
|
|
|
44
|
-
启动 Vite dev server 后,插件会自动写入常见 AI 客户端的项目级 MCP 配置,服务名默认是 `vue-mcp-next
|
|
45
|
+
启动 Vite dev server 后,插件会自动写入常见 AI 客户端的项目级 MCP 配置,服务名默认是 `vue-mcp-next`。自动配置只会在缺少同名 server 条目时新增配置;如果用户已经配置了 `vue-mcp-next`,插件不会重复写入或覆盖原配置。
|
|
45
46
|
|
|
46
|
-
| 客户端 | 自动配置文件 |
|
|
47
|
-
|
|
48
|
-
| Cursor | `.cursor/mcp.json` |
|
|
49
|
-
| Codex | `.codex/config.toml` |
|
|
50
|
-
| Claude Code | `.mcp.json` |
|
|
51
|
-
| Trae | `.trae/mcp.json` |
|
|
47
|
+
| 客户端 | 自动配置文件 | 默认端点 |
|
|
48
|
+
|---|---|---|
|
|
49
|
+
| Cursor | `.cursor/mcp.json` | SSE |
|
|
50
|
+
| Codex | `.codex/config.toml` | Streamable HTTP |
|
|
51
|
+
| Claude Code | `.mcp.json` | SSE |
|
|
52
|
+
| Trae | `.trae/mcp.json` | SSE |
|
|
52
53
|
|
|
53
|
-
实际端口以启动日志中的 `MCP:
|
|
54
|
+
实际端口以启动日志中的 `MCP: SSE server is running at ...` 和 `MCP: Streamable HTTP server is running at ...` 为准。
|
|
54
55
|
|
|
55
56
|
### 手动配置 MCP 客户端
|
|
56
57
|
|
|
57
|
-
如果你不想使用自动配置,或需要把地址复制到其他支持 HTTP MCP 的客户端,可以手动配置当前 Vite dev server 的
|
|
58
|
+
如果你不想使用自动配置,或需要把地址复制到其他支持 HTTP MCP 的客户端,可以手动配置当前 Vite dev server 的 MCP 地址。
|
|
58
59
|
|
|
59
60
|
Cursor、Claude Code、Trae 等 JSON 配置客户端可以使用:
|
|
60
61
|
|
|
@@ -62,6 +63,7 @@ Cursor、Claude Code、Trae 等 JSON 配置客户端可以使用:
|
|
|
62
63
|
{
|
|
63
64
|
"mcpServers": {
|
|
64
65
|
"vue-mcp-next": {
|
|
66
|
+
"type": "sse",
|
|
65
67
|
"url": "http://localhost:5173/__mcp/sse"
|
|
66
68
|
}
|
|
67
69
|
}
|
|
@@ -72,7 +74,7 @@ Codex 使用 TOML 配置:
|
|
|
72
74
|
|
|
73
75
|
```toml
|
|
74
76
|
[mcp_servers.vue-mcp-next]
|
|
75
|
-
url = "http://localhost:5173/__mcp/
|
|
77
|
+
url = "http://localhost:5173/__mcp/mcp"
|
|
76
78
|
```
|
|
77
79
|
|
|
78
80
|
`5173` 是示例端口。若 Vite 使用了其他端口,请替换为启动日志中打印的 MCP 地址。
|
|
@@ -128,7 +130,7 @@ vueMcpNext({
|
|
|
128
130
|
|
|
129
131
|
| 配置 | 类型 | 默认值 | 说明 |
|
|
130
132
|
|---|---|---|---|
|
|
131
|
-
| `mcpPath` | `string` | `'/__mcp'` | MCP 服务挂载路径,实际 SSE 地址是 `${mcpPath}/sse` |
|
|
133
|
+
| `mcpPath` | `string` | `'/__mcp'` | MCP 服务挂载路径,实际 SSE 地址是 `${mcpPath}/sse`,Streamable HTTP 地址是 `${mcpPath}/mcp` |
|
|
132
134
|
| `host` | `string` | `'localhost'` | 打印 MCP 地址和写入 MCP 客户端配置时使用的 host |
|
|
133
135
|
| `printUrl` | `boolean` | `true` | 是否在 Vite 启动日志中打印 MCP SSE 地址 |
|
|
134
136
|
| `mcpClients` | `{ cursor?: boolean; codex?: boolean; claudeCode?: boolean; trae?: boolean; serverName?: string }` | 全部启用 | 是否自动写入 Cursor、Codex、Claude Code、Trae 的项目级 MCP 配置 |
|
|
@@ -366,7 +368,8 @@ pnpm run play
|
|
|
366
368
|
|
|
367
369
|
```text
|
|
368
370
|
Local: http://localhost:3456/
|
|
369
|
-
MCP:
|
|
371
|
+
MCP: SSE server is running at http://localhost:3456/__mcp/sse
|
|
372
|
+
MCP: Streamable HTTP server is running at http://localhost:3456/__mcp/mcp
|
|
370
373
|
```
|
|
371
374
|
|
|
372
375
|
当前 playground 页面入口为:
|
package/dist/index.cjs
CHANGED
|
@@ -846,18 +846,39 @@ function createMcpServer(ctx, vite) {
|
|
|
846
846
|
|
|
847
847
|
// src/mcp/transport.ts
|
|
848
848
|
var import_sse = require("@modelcontextprotocol/sdk/server/sse.js");
|
|
849
|
-
|
|
849
|
+
var import_streamableHttp = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
|
|
850
|
+
function setupMcpTransport(base, createServer, vite) {
|
|
850
851
|
const transports = /* @__PURE__ */ new Map();
|
|
851
852
|
vite.middlewares.use(`${base}/sse`, (_req, res) => {
|
|
852
853
|
const transport = new import_sse.SSEServerTransport(`${base}/messages`, res);
|
|
853
|
-
|
|
854
|
+
const server = createServer();
|
|
855
|
+
transports.set(transport.sessionId, { server, transport });
|
|
854
856
|
res.on("close", () => {
|
|
855
857
|
transports.delete(transport.sessionId);
|
|
858
|
+
void server.close();
|
|
856
859
|
});
|
|
857
860
|
void server.connect(transport).catch((error) => {
|
|
858
861
|
res.destroy(error instanceof Error ? error : new Error(String(error)));
|
|
859
862
|
});
|
|
860
863
|
});
|
|
864
|
+
vite.middlewares.use(`${base}/mcp`, (req, res) => {
|
|
865
|
+
if (req.method !== "POST") {
|
|
866
|
+
res.statusCode = 405;
|
|
867
|
+
res.end("Method Not Allowed");
|
|
868
|
+
return;
|
|
869
|
+
}
|
|
870
|
+
const transport = new import_streamableHttp.StreamableHTTPServerTransport({
|
|
871
|
+
sessionIdGenerator: void 0
|
|
872
|
+
});
|
|
873
|
+
const server = createServer();
|
|
874
|
+
res.on("close", () => {
|
|
875
|
+
void transport.close();
|
|
876
|
+
void server.close();
|
|
877
|
+
});
|
|
878
|
+
void server.connect(transport).then(() => transport.handleRequest(req, res)).catch((error) => {
|
|
879
|
+
res.destroy(error instanceof Error ? error : new Error(String(error)));
|
|
880
|
+
});
|
|
881
|
+
});
|
|
861
882
|
vite.middlewares.use(`${base}/messages`, (req, res) => {
|
|
862
883
|
if (req.method !== "POST") {
|
|
863
884
|
res.statusCode = 405;
|
|
@@ -871,13 +892,13 @@ function setupMcpTransport(base, server, vite) {
|
|
|
871
892
|
res.end("Bad Request");
|
|
872
893
|
return;
|
|
873
894
|
}
|
|
874
|
-
const
|
|
875
|
-
if (!
|
|
895
|
+
const entry = transports.get(sessionId);
|
|
896
|
+
if (!entry) {
|
|
876
897
|
res.statusCode = 404;
|
|
877
898
|
res.end("Not Found");
|
|
878
899
|
return;
|
|
879
900
|
}
|
|
880
|
-
void transport.handlePostMessage(req, res).catch((error) => {
|
|
901
|
+
void entry.transport.handlePostMessage(req, res).catch((error) => {
|
|
881
902
|
res.destroy(error instanceof Error ? error : new Error(String(error)));
|
|
882
903
|
});
|
|
883
904
|
});
|
|
@@ -1195,7 +1216,7 @@ function createRuntimeInjectionController(options, getConfig) {
|
|
|
1195
1216
|
if (id !== RESOLVED_VIRTUAL_RUNTIME_ID) {
|
|
1196
1217
|
return void 0;
|
|
1197
1218
|
}
|
|
1198
|
-
return "import { startRuntimeClient } from 'vite-plugin-vue-mcp-next/runtime/client';\nvoid startRuntimeClient();";
|
|
1219
|
+
return "import { startRuntimeClient } from '@xiaou66/vite-plugin-vue-mcp-next/runtime/client';\nvoid startRuntimeClient();";
|
|
1199
1220
|
},
|
|
1200
1221
|
transformIndexHtml(html) {
|
|
1201
1222
|
if (options.appendTo) {
|
|
@@ -1253,7 +1274,7 @@ function replaceOrAppendOwnedBlock(current, options) {
|
|
|
1253
1274
|
const block = createCodexServerBlock(options);
|
|
1254
1275
|
const matcher = createOwnedBlockMatcher(options.serverName);
|
|
1255
1276
|
if (matcher.test(current)) {
|
|
1256
|
-
return current
|
|
1277
|
+
return ensureTrailingNewline(current);
|
|
1257
1278
|
}
|
|
1258
1279
|
const separator = current.trim() ? "\n\n" : "";
|
|
1259
1280
|
return `${trimEndNewline(current)}${separator}${block}`;
|
|
@@ -1295,6 +1316,10 @@ async function readOptionalTextFile(filePath) {
|
|
|
1295
1316
|
function trimEndNewline(value) {
|
|
1296
1317
|
return value.replace(/\n+$/u, "");
|
|
1297
1318
|
}
|
|
1319
|
+
function ensureTrailingNewline(value) {
|
|
1320
|
+
return value.endsWith("\n") ? value : `${value}
|
|
1321
|
+
`;
|
|
1322
|
+
}
|
|
1298
1323
|
function escapeRegExp(value) {
|
|
1299
1324
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1300
1325
|
}
|
|
@@ -1316,7 +1341,10 @@ async function updateJsonMcpClientConfig(options) {
|
|
|
1316
1341
|
return;
|
|
1317
1342
|
}
|
|
1318
1343
|
const mcpServers = isPlainRecord(config.mcpServers) ? config.mcpServers : {};
|
|
1319
|
-
mcpServers
|
|
1344
|
+
if (Object.hasOwn(mcpServers, options.serverName)) {
|
|
1345
|
+
return;
|
|
1346
|
+
}
|
|
1347
|
+
mcpServers[options.serverName] = { type: "sse", url: options.mcpUrl };
|
|
1320
1348
|
config.mcpServers = mcpServers;
|
|
1321
1349
|
await import_promises2.default.mkdir(import_node_path3.default.dirname(options.configPath), { recursive: true });
|
|
1322
1350
|
await import_promises2.default.writeFile(
|
|
@@ -1361,7 +1389,7 @@ function isNodeError2(error) {
|
|
|
1361
1389
|
}
|
|
1362
1390
|
|
|
1363
1391
|
// src/plugin/mcpClientConfig/index.ts
|
|
1364
|
-
async function updateMcpClientConfigs(root,
|
|
1392
|
+
async function updateMcpClientConfigs(root, sseUrl, streamableHttpUrl, options) {
|
|
1365
1393
|
const serverName = options.serverName;
|
|
1366
1394
|
const jobs = [];
|
|
1367
1395
|
if (options.cursor) {
|
|
@@ -1369,7 +1397,7 @@ async function updateMcpClientConfigs(root, mcpUrl, options) {
|
|
|
1369
1397
|
updateJsonMcpClientConfig({
|
|
1370
1398
|
clientName: "Cursor",
|
|
1371
1399
|
configPath: import_node_path4.default.join(root, ".cursor", "mcp.json"),
|
|
1372
|
-
mcpUrl,
|
|
1400
|
+
mcpUrl: sseUrl,
|
|
1373
1401
|
serverName
|
|
1374
1402
|
})
|
|
1375
1403
|
);
|
|
@@ -1378,7 +1406,7 @@ async function updateMcpClientConfigs(root, mcpUrl, options) {
|
|
|
1378
1406
|
jobs.push(
|
|
1379
1407
|
updateCodexMcpClientConfig({
|
|
1380
1408
|
configPath: import_node_path4.default.join(root, ".codex", "config.toml"),
|
|
1381
|
-
mcpUrl,
|
|
1409
|
+
mcpUrl: streamableHttpUrl,
|
|
1382
1410
|
serverName
|
|
1383
1411
|
})
|
|
1384
1412
|
);
|
|
@@ -1388,7 +1416,7 @@ async function updateMcpClientConfigs(root, mcpUrl, options) {
|
|
|
1388
1416
|
updateJsonMcpClientConfig({
|
|
1389
1417
|
clientName: "Claude Code",
|
|
1390
1418
|
configPath: import_node_path4.default.join(root, ".mcp.json"),
|
|
1391
|
-
mcpUrl,
|
|
1419
|
+
mcpUrl: sseUrl,
|
|
1392
1420
|
serverName
|
|
1393
1421
|
})
|
|
1394
1422
|
);
|
|
@@ -1398,7 +1426,7 @@ async function updateMcpClientConfigs(root, mcpUrl, options) {
|
|
|
1398
1426
|
updateJsonMcpClientConfig({
|
|
1399
1427
|
clientName: "Trae",
|
|
1400
1428
|
configPath: import_node_path4.default.join(root, ".trae", "mcp.json"),
|
|
1401
|
-
mcpUrl,
|
|
1429
|
+
mcpUrl: sseUrl,
|
|
1402
1430
|
serverName
|
|
1403
1431
|
})
|
|
1404
1432
|
);
|
|
@@ -1434,8 +1462,11 @@ function vueMcpNext(userOptions = {}) {
|
|
|
1434
1462
|
timeout: -1
|
|
1435
1463
|
}
|
|
1436
1464
|
);
|
|
1437
|
-
|
|
1438
|
-
|
|
1465
|
+
setupMcpTransport(
|
|
1466
|
+
options.mcpPath,
|
|
1467
|
+
() => createMcpServer(ctx, server),
|
|
1468
|
+
server
|
|
1469
|
+
);
|
|
1439
1470
|
server.ws.on(
|
|
1440
1471
|
"vite-plugin-vue-mcp-next:page-connected",
|
|
1441
1472
|
(payload) => {
|
|
@@ -1462,12 +1493,21 @@ function vueMcpNext(userOptions = {}) {
|
|
|
1462
1493
|
}
|
|
1463
1494
|
);
|
|
1464
1495
|
const port = String(server.config.server.port || 5173);
|
|
1465
|
-
const
|
|
1496
|
+
const mcpSseUrl = `http://${options.host}:${port}${options.mcpPath}/sse`;
|
|
1497
|
+
const mcpStreamableHttpUrl = `http://${options.host}:${port}${options.mcpPath}/mcp`;
|
|
1466
1498
|
const root = (0, import_vite2.searchForWorkspaceRoot)(server.config.root);
|
|
1467
|
-
await updateMcpClientConfigs(
|
|
1499
|
+
await updateMcpClientConfigs(
|
|
1500
|
+
root,
|
|
1501
|
+
mcpSseUrl,
|
|
1502
|
+
mcpStreamableHttpUrl,
|
|
1503
|
+
options.mcpClients
|
|
1504
|
+
);
|
|
1468
1505
|
if (options.printUrl) {
|
|
1469
1506
|
setTimeout(() => {
|
|
1470
|
-
console.log(` \u279C MCP:
|
|
1507
|
+
console.log(` \u279C MCP: SSE server is running at ${mcpSseUrl}`);
|
|
1508
|
+
console.log(
|
|
1509
|
+
` \u279C MCP: Streamable HTTP server is running at ${mcpStreamableHttpUrl}`
|
|
1510
|
+
);
|
|
1471
1511
|
}, 300);
|
|
1472
1512
|
}
|
|
1473
1513
|
server.httpServer?.once("close", () => {
|