@xiaou66/vite-plugin-vue-mcp-next 0.0.8 → 1.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/README.md CHANGED
@@ -43,14 +43,18 @@ SSE: http://localhost:<vite-port>/__mcp/sse
43
43
  Streamable HTTP: http://localhost:<vite-port>/__mcp/mcp
44
44
  ```
45
45
 
46
- 启动 Vite dev server 后,插件会自动写入常见 AI 客户端的项目级 MCP 配置,服务名默认是 `vue-mcp-next`。自动配置只会在缺少同名 server 条目时新增配置;如果用户已经配置了 `vue-mcp-next`,插件不会重复写入或覆盖原配置。
46
+ 启动 Vite dev server 后,插件会按项目中已经存在的客户端入口自动写入项目级 MCP 配置,服务名默认是 `vue-mcp-next`。自动配置只会在缺少同名 server 条目时新增配置;如果用户已经配置了 `vue-mcp-next`,插件不会重复写入、覆盖原配置或改写用户自定义字段。
47
47
 
48
- | 客户端 | 自动配置文件 | 默认端点 |
49
- | ----------- | -------------------- | --------------- |
50
- | Cursor | `.cursor/mcp.json` | SSE |
51
- | Codex | `.codex/config.toml` | Streamable HTTP |
52
- | Claude Code | `.mcp.json` | SSE |
53
- | Trae | `.trae/mcp.json` | SSE |
48
+ 默认自动探测规则如下:
49
+
50
+ | 客户端 | 自动探测入口 | 自动配置文件 | 默认端点 |
51
+ | ----------- | ------------ | -------------------- | --------------- |
52
+ | Cursor | `.cursor/` | `.cursor/mcp.json` | SSE |
53
+ | Codex | `.codex/` | `.codex/config.toml` | Streamable HTTP |
54
+ | Claude Code | `.mcp.json` | `.mcp.json` | SSE |
55
+ | Trae | `.trae/` | `.trae/mcp.json` | SSE |
56
+
57
+ 如果项目中没有对应入口,默认不会创建该客户端配置。需要强制创建时,可以在 `mcpClients` 中显式设置对应客户端为 `true`;需要禁用时显式设置为 `false`。
54
58
 
55
59
  实际端口以启动日志中的 `MCP: SSE server is running at ...` 和 `MCP: Streamable HTTP server is running at ...` 为准。
56
60
 
@@ -82,6 +86,8 @@ url = "http://localhost:5173/__mcp/mcp"
82
86
 
83
87
  ## 完整配置
84
88
 
89
+ `mcpClients` 中的布尔值保留为开关语义:默认解析后为 `true`,但写入阶段会先做项目入口自动探测;用户在配置中显式写出 `true` 时表示强制创建对应客户端配置。
90
+
85
91
  ```ts
86
92
  vueMcpNext({
87
93
  mcpPath: '/__mcp',
@@ -147,8 +153,8 @@ vueMcpNext({
147
153
  | `mcpPath` | `string` | `'/__mcp'` | MCP 服务挂载路径,实际 SSE 地址是 `${mcpPath}/sse`,Streamable HTTP 地址是 `${mcpPath}/mcp` |
148
154
  | `host` | `string` | `'localhost'` | 打印 MCP 地址和写入 MCP 客户端配置时使用的 host |
149
155
  | `printUrl` | `boolean` | `true` | 是否在 Vite 启动日志中打印 MCP SSE 地址 |
150
- | `mcpClients` | `{ cursor?: boolean; codex?: boolean; claudeCode?: boolean; trae?: boolean; serverName?: string }` | 全部启用 | 是否自动写入 Cursor、Codex、Claude Code、Trae 的项目级 MCP 配置 |
151
- | `updateCursorMcpJson` | `boolean \| { enabled: boolean; serverName?: string }` | `true` | 兼容旧配置,建议新项目使用 `mcpClients` |
156
+ | `mcpClients` | `{ cursor?: boolean; codex?: boolean; claudeCode?: boolean; trae?: boolean; serverName?: string }` | 自动探测 | 是否写入 Cursor、Codex、Claude Code、Trae 的项目级 MCP 配置;默认只处理项目中已有入口,显式 `true` 强制创建 |
157
+ | `updateCursorMcpJson` | `boolean \| { enabled: boolean; serverName?: string }` | 自动探测 | 兼容旧配置;默认只在 `.cursor` 已存在时写入,建议新项目使用 `mcpClients` |
152
158
  | `appendTo` | `string \| RegExp` | `undefined` | 非 HTML 入口注入点。配置后会在匹配入口模块前追加 runtime import |
153
159
  | `screenshot` | `ScreenshotOptions` | CDP 优先,snapdom 降级 | 页面截图配置,控制真截图、DOM 降级截图、体积上限和 snapdom 扩展 |
154
160
  | `screenshot.type` | `'path' \| 'base64'` | `'path'` | 项目级控制截图返回文件路径还是 base64 数据 |
@@ -362,7 +368,6 @@ export function createMaskPlugin(options: { selectors: string[] }) {
362
368
  | ---------------- | ------------------------- | ------------------------------- | ----------------------------------------------------------------- |
363
369
  | `list_pages` | 无 | `entries`、`pages`、`cdpError?` | 返回 Vite HTML 入口、runtime 页面和 CDP target |
364
370
  | `reload_page` | `pageId?`、`ignoreCache?` | `ok`、`source`、`ignoreCache?` | 刷新目标页面;CDP 可用时使用无缓存刷新,Runtime Hook 只能普通刷新 |
365
- | `get_page_state` | `pageId?` | 页面状态 | 预留页面状态工具名 |
366
371
 
367
372
  `list_pages` 的 `pages` 中可能出现两类页面:
368
373
 
package/dist/index.cjs CHANGED
@@ -58,7 +58,6 @@ var DEFAULT_SCREENSHOT_SAVE_DIR = ".vite-mcp/screenshot";
58
58
  var MCP_TOOL_NAMES = {
59
59
  listPages: "list_pages",
60
60
  reloadPage: "reload_page",
61
- getPageState: "get_page_state",
62
61
  getDomTree: "get_dom_tree",
63
62
  queryDom: "query_dom",
64
63
  takeScreenshot: "take_screenshot",
@@ -1772,6 +1771,7 @@ function getPluginPath(plugin) {
1772
1771
  }
1773
1772
 
1774
1773
  // src/plugin/mcpClientConfig/index.ts
1774
+ var import_promises4 = __toESM(require("fs/promises"), 1);
1775
1775
  var import_node_path6 = __toESM(require("path"), 1);
1776
1776
 
1777
1777
  // src/plugin/mcpClientConfig/codexConfig.ts
@@ -1908,10 +1908,17 @@ function isNodeError2(error) {
1908
1908
  }
1909
1909
 
1910
1910
  // src/plugin/mcpClientConfig/index.ts
1911
- async function updateMcpClientConfigs(root, sseUrl, streamableHttpUrl, options) {
1911
+ async function updateMcpClientConfigs(root, sseUrl, streamableHttpUrl, options, userOptions = {}) {
1912
1912
  const serverName = options.serverName;
1913
1913
  const jobs = [];
1914
- if (options.cursor) {
1914
+ if (await shouldUpdateClientConfig({
1915
+ root,
1916
+ clientName: "cursor",
1917
+ enabled: options.cursor,
1918
+ entryPath: import_node_path6.default.join(root, ".cursor"),
1919
+ entryKind: "directory",
1920
+ userOptions
1921
+ })) {
1915
1922
  jobs.push(
1916
1923
  updateJsonMcpClientConfig({
1917
1924
  clientName: "Cursor",
@@ -1921,7 +1928,14 @@ async function updateMcpClientConfigs(root, sseUrl, streamableHttpUrl, options)
1921
1928
  })
1922
1929
  );
1923
1930
  }
1924
- if (options.codex) {
1931
+ if (await shouldUpdateClientConfig({
1932
+ root,
1933
+ clientName: "codex",
1934
+ enabled: options.codex,
1935
+ entryPath: import_node_path6.default.join(root, ".codex"),
1936
+ entryKind: "directory",
1937
+ userOptions
1938
+ })) {
1925
1939
  jobs.push(
1926
1940
  updateCodexMcpClientConfig({
1927
1941
  configPath: import_node_path6.default.join(root, ".codex", "config.toml"),
@@ -1930,7 +1944,14 @@ async function updateMcpClientConfigs(root, sseUrl, streamableHttpUrl, options)
1930
1944
  })
1931
1945
  );
1932
1946
  }
1933
- if (options.claudeCode) {
1947
+ if (await shouldUpdateClientConfig({
1948
+ root,
1949
+ clientName: "claudeCode",
1950
+ enabled: options.claudeCode,
1951
+ entryPath: import_node_path6.default.join(root, ".mcp.json"),
1952
+ entryKind: "file",
1953
+ userOptions
1954
+ })) {
1934
1955
  jobs.push(
1935
1956
  updateJsonMcpClientConfig({
1936
1957
  clientName: "Claude Code",
@@ -1940,7 +1961,14 @@ async function updateMcpClientConfigs(root, sseUrl, streamableHttpUrl, options)
1940
1961
  })
1941
1962
  );
1942
1963
  }
1943
- if (options.trae) {
1964
+ if (await shouldUpdateClientConfig({
1965
+ root,
1966
+ clientName: "trae",
1967
+ enabled: options.trae,
1968
+ entryPath: import_node_path6.default.join(root, ".trae"),
1969
+ entryKind: "directory",
1970
+ userOptions
1971
+ })) {
1944
1972
  jobs.push(
1945
1973
  updateJsonMcpClientConfig({
1946
1974
  clientName: "Trae",
@@ -1952,6 +1980,41 @@ async function updateMcpClientConfigs(root, sseUrl, streamableHttpUrl, options)
1952
1980
  }
1953
1981
  await Promise.all(jobs);
1954
1982
  }
1983
+ async function shouldUpdateClientConfig(options) {
1984
+ if (!options.enabled) {
1985
+ return false;
1986
+ }
1987
+ if (isClientExplicitlyConfigured(options.clientName, options.userOptions)) {
1988
+ return true;
1989
+ }
1990
+ return hasExpectedEntry(options.entryPath, options.entryKind);
1991
+ }
1992
+ function isClientExplicitlyConfigured(clientName, userOptions) {
1993
+ if (Object.hasOwn(userOptions.mcpClients ?? {}, clientName)) {
1994
+ return true;
1995
+ }
1996
+ return clientName === "cursor" && userOptions.updateCursorMcpJson !== void 0;
1997
+ }
1998
+ async function hasExpectedEntry(entryPath, entryKind) {
1999
+ try {
2000
+ const stat = await import_promises4.default.stat(entryPath);
2001
+ return entryKind === "directory" ? stat.isDirectory() : stat.isFile();
2002
+ } catch (error) {
2003
+ if (isNodeError3(error) && error.code === "ENOENT") {
2004
+ return false;
2005
+ }
2006
+ console.warn(
2007
+ `[vite-plugin-vue-mcp-next] Failed to inspect MCP client entry at ${entryPath}: ${formatError3(error)}`
2008
+ );
2009
+ return false;
2010
+ }
2011
+ }
2012
+ function formatError3(error) {
2013
+ return error instanceof Error ? error.message : String(error);
2014
+ }
2015
+ function isNodeError3(error) {
2016
+ return error instanceof Error && "code" in error;
2017
+ }
1955
2018
 
1956
2019
  // src/plugin/createPlugin.ts
1957
2020
  var import_vite_dev_rpc = require("vite-dev-rpc");
@@ -2021,7 +2084,8 @@ function vueMcpNext(userOptions = {}) {
2021
2084
  root,
2022
2085
  mcpSseUrl,
2023
2086
  mcpStreamableHttpUrl,
2024
- options.mcpClients
2087
+ options.mcpClients,
2088
+ userOptions
2025
2089
  );
2026
2090
  if (options.printUrl) {
2027
2091
  setTimeout(() => {