@xiaou66/vite-plugin-vue-mcp-next 1.0.0 → 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/dist/index.d.cts CHANGED
@@ -29,9 +29,9 @@ interface VueMcpNextOptions {
29
29
  readonly host?: string;
30
30
  /** 是否在 Vite 启动日志中打印 MCP 地址,默认开启方便开发者复制到 MCP 客户端。 */
31
31
  readonly printUrl?: boolean;
32
- /** 是否写入 Cursor MCP 配置;只在 `.cursor` 已存在时生效,避免擅自创建编辑器配置目录。 */
32
+ /** 是否写入 Cursor MCP 配置;默认只在 `.cursor` 已存在时写入,显式 `true` 会创建配置。 */
33
33
  readonly updateCursorMcpJson?: boolean | CursorMcpConfig;
34
- /** 是否写入常见 AI 客户端的项目级 MCP 配置,默认启用 Cursor、Codex、Claude Code 和 Trae。 */
34
+ /** 是否写入常见 AI 客户端的项目级 MCP 配置;默认按项目已有客户端入口自动探测。 */
35
35
  readonly mcpClients?: McpClientConfigOptions;
36
36
  /** 非 HTML 入口的运行时脚本注入点,用于兼容不直接使用 `index.html` 的项目。 */
37
37
  readonly appendTo?: string | RegExp;
@@ -54,7 +54,7 @@ interface VueMcpNextOptions {
54
54
  * 该配置只负责本地开发体验,不应强行修改未启用 Cursor 的项目。
55
55
  */
56
56
  interface CursorMcpConfig {
57
- /** 是否启用 Cursor 配置写入,适合团队项目显式关闭自动改配置。 */
57
+ /** 是否启用 Cursor 配置写入;显式启用会创建 `.cursor/mcp.json`,显式关闭会跳过。 */
58
58
  readonly enabled: boolean;
59
59
  /** Cursor 展示的 MCP 服务名,用于同一项目存在多个 MCP 服务时避免冲突。 */
60
60
  readonly serverName?: string;
@@ -66,13 +66,13 @@ interface CursorMcpConfig {
66
66
  * 集中配置可以避免为每个客户端暴露一组重复选项。
67
67
  */
68
68
  interface McpClientConfigOptions {
69
- /** 是否写入 Cursor 的 `.cursor/mcp.json`,适合 Cursor 用户开箱即用。 */
69
+ /** 是否写入 Cursor 的 `.cursor/mcp.json`;默认只在 `.cursor` 目录已存在时自动写入。 */
70
70
  readonly cursor?: boolean;
71
- /** 是否写入 Codex 的 `.codex/config.toml`,适合 Codex 项目级 MCP 配置。 */
71
+ /** 是否写入 Codex 的 `.codex/config.toml`;默认只在 `.codex` 目录已存在时自动写入。 */
72
72
  readonly codex?: boolean;
73
- /** 是否写入 Claude Code 的 `.mcp.json`,采用官方项目级 MCP 配置入口。 */
73
+ /** 是否写入 Claude Code 的 `.mcp.json`;默认只在根目录 `.mcp.json` 已存在时自动写入。 */
74
74
  readonly claudeCode?: boolean;
75
- /** 是否写入 Trae 的 `.trae/mcp.json`,与 Trae 项目级 MCP 文档保持一致。 */
75
+ /** 是否写入 Trae 的 `.trae/mcp.json`;默认只在 `.trae` 目录已存在时自动写入。 */
76
76
  readonly trae?: boolean;
77
77
  /** MCP 客户端中展示的服务名,同一项目存在多个 MCP 服务时用于避免冲突。 */
78
78
  readonly serverName?: string;
package/dist/index.d.ts CHANGED
@@ -29,9 +29,9 @@ interface VueMcpNextOptions {
29
29
  readonly host?: string;
30
30
  /** 是否在 Vite 启动日志中打印 MCP 地址,默认开启方便开发者复制到 MCP 客户端。 */
31
31
  readonly printUrl?: boolean;
32
- /** 是否写入 Cursor MCP 配置;只在 `.cursor` 已存在时生效,避免擅自创建编辑器配置目录。 */
32
+ /** 是否写入 Cursor MCP 配置;默认只在 `.cursor` 已存在时写入,显式 `true` 会创建配置。 */
33
33
  readonly updateCursorMcpJson?: boolean | CursorMcpConfig;
34
- /** 是否写入常见 AI 客户端的项目级 MCP 配置,默认启用 Cursor、Codex、Claude Code 和 Trae。 */
34
+ /** 是否写入常见 AI 客户端的项目级 MCP 配置;默认按项目已有客户端入口自动探测。 */
35
35
  readonly mcpClients?: McpClientConfigOptions;
36
36
  /** 非 HTML 入口的运行时脚本注入点,用于兼容不直接使用 `index.html` 的项目。 */
37
37
  readonly appendTo?: string | RegExp;
@@ -54,7 +54,7 @@ interface VueMcpNextOptions {
54
54
  * 该配置只负责本地开发体验,不应强行修改未启用 Cursor 的项目。
55
55
  */
56
56
  interface CursorMcpConfig {
57
- /** 是否启用 Cursor 配置写入,适合团队项目显式关闭自动改配置。 */
57
+ /** 是否启用 Cursor 配置写入;显式启用会创建 `.cursor/mcp.json`,显式关闭会跳过。 */
58
58
  readonly enabled: boolean;
59
59
  /** Cursor 展示的 MCP 服务名,用于同一项目存在多个 MCP 服务时避免冲突。 */
60
60
  readonly serverName?: string;
@@ -66,13 +66,13 @@ interface CursorMcpConfig {
66
66
  * 集中配置可以避免为每个客户端暴露一组重复选项。
67
67
  */
68
68
  interface McpClientConfigOptions {
69
- /** 是否写入 Cursor 的 `.cursor/mcp.json`,适合 Cursor 用户开箱即用。 */
69
+ /** 是否写入 Cursor 的 `.cursor/mcp.json`;默认只在 `.cursor` 目录已存在时自动写入。 */
70
70
  readonly cursor?: boolean;
71
- /** 是否写入 Codex 的 `.codex/config.toml`,适合 Codex 项目级 MCP 配置。 */
71
+ /** 是否写入 Codex 的 `.codex/config.toml`;默认只在 `.codex` 目录已存在时自动写入。 */
72
72
  readonly codex?: boolean;
73
- /** 是否写入 Claude Code 的 `.mcp.json`,采用官方项目级 MCP 配置入口。 */
73
+ /** 是否写入 Claude Code 的 `.mcp.json`;默认只在根目录 `.mcp.json` 已存在时自动写入。 */
74
74
  readonly claudeCode?: boolean;
75
- /** 是否写入 Trae 的 `.trae/mcp.json`,与 Trae 项目级 MCP 文档保持一致。 */
75
+ /** 是否写入 Trae 的 `.trae/mcp.json`;默认只在 `.trae` 目录已存在时自动写入。 */
76
76
  readonly trae?: boolean;
77
77
  /** MCP 客户端中展示的服务名,同一项目存在多个 MCP 服务时用于避免冲突。 */
78
78
  readonly serverName?: string;
package/dist/index.js CHANGED
@@ -1734,6 +1734,7 @@ function getPluginPath(plugin) {
1734
1734
  }
1735
1735
 
1736
1736
  // src/plugin/mcpClientConfig/index.ts
1737
+ import fs4 from "fs/promises";
1737
1738
  import path5 from "path";
1738
1739
 
1739
1740
  // src/plugin/mcpClientConfig/codexConfig.ts
@@ -1870,10 +1871,17 @@ function isNodeError2(error) {
1870
1871
  }
1871
1872
 
1872
1873
  // src/plugin/mcpClientConfig/index.ts
1873
- async function updateMcpClientConfigs(root, sseUrl, streamableHttpUrl, options) {
1874
+ async function updateMcpClientConfigs(root, sseUrl, streamableHttpUrl, options, userOptions = {}) {
1874
1875
  const serverName = options.serverName;
1875
1876
  const jobs = [];
1876
- if (options.cursor) {
1877
+ if (await shouldUpdateClientConfig({
1878
+ root,
1879
+ clientName: "cursor",
1880
+ enabled: options.cursor,
1881
+ entryPath: path5.join(root, ".cursor"),
1882
+ entryKind: "directory",
1883
+ userOptions
1884
+ })) {
1877
1885
  jobs.push(
1878
1886
  updateJsonMcpClientConfig({
1879
1887
  clientName: "Cursor",
@@ -1883,7 +1891,14 @@ async function updateMcpClientConfigs(root, sseUrl, streamableHttpUrl, options)
1883
1891
  })
1884
1892
  );
1885
1893
  }
1886
- if (options.codex) {
1894
+ if (await shouldUpdateClientConfig({
1895
+ root,
1896
+ clientName: "codex",
1897
+ enabled: options.codex,
1898
+ entryPath: path5.join(root, ".codex"),
1899
+ entryKind: "directory",
1900
+ userOptions
1901
+ })) {
1887
1902
  jobs.push(
1888
1903
  updateCodexMcpClientConfig({
1889
1904
  configPath: path5.join(root, ".codex", "config.toml"),
@@ -1892,7 +1907,14 @@ async function updateMcpClientConfigs(root, sseUrl, streamableHttpUrl, options)
1892
1907
  })
1893
1908
  );
1894
1909
  }
1895
- if (options.claudeCode) {
1910
+ if (await shouldUpdateClientConfig({
1911
+ root,
1912
+ clientName: "claudeCode",
1913
+ enabled: options.claudeCode,
1914
+ entryPath: path5.join(root, ".mcp.json"),
1915
+ entryKind: "file",
1916
+ userOptions
1917
+ })) {
1896
1918
  jobs.push(
1897
1919
  updateJsonMcpClientConfig({
1898
1920
  clientName: "Claude Code",
@@ -1902,7 +1924,14 @@ async function updateMcpClientConfigs(root, sseUrl, streamableHttpUrl, options)
1902
1924
  })
1903
1925
  );
1904
1926
  }
1905
- if (options.trae) {
1927
+ if (await shouldUpdateClientConfig({
1928
+ root,
1929
+ clientName: "trae",
1930
+ enabled: options.trae,
1931
+ entryPath: path5.join(root, ".trae"),
1932
+ entryKind: "directory",
1933
+ userOptions
1934
+ })) {
1906
1935
  jobs.push(
1907
1936
  updateJsonMcpClientConfig({
1908
1937
  clientName: "Trae",
@@ -1914,6 +1943,41 @@ async function updateMcpClientConfigs(root, sseUrl, streamableHttpUrl, options)
1914
1943
  }
1915
1944
  await Promise.all(jobs);
1916
1945
  }
1946
+ async function shouldUpdateClientConfig(options) {
1947
+ if (!options.enabled) {
1948
+ return false;
1949
+ }
1950
+ if (isClientExplicitlyConfigured(options.clientName, options.userOptions)) {
1951
+ return true;
1952
+ }
1953
+ return hasExpectedEntry(options.entryPath, options.entryKind);
1954
+ }
1955
+ function isClientExplicitlyConfigured(clientName, userOptions) {
1956
+ if (Object.hasOwn(userOptions.mcpClients ?? {}, clientName)) {
1957
+ return true;
1958
+ }
1959
+ return clientName === "cursor" && userOptions.updateCursorMcpJson !== void 0;
1960
+ }
1961
+ async function hasExpectedEntry(entryPath, entryKind) {
1962
+ try {
1963
+ const stat = await fs4.stat(entryPath);
1964
+ return entryKind === "directory" ? stat.isDirectory() : stat.isFile();
1965
+ } catch (error) {
1966
+ if (isNodeError3(error) && error.code === "ENOENT") {
1967
+ return false;
1968
+ }
1969
+ console.warn(
1970
+ `[vite-plugin-vue-mcp-next] Failed to inspect MCP client entry at ${entryPath}: ${formatError3(error)}`
1971
+ );
1972
+ return false;
1973
+ }
1974
+ }
1975
+ function formatError3(error) {
1976
+ return error instanceof Error ? error.message : String(error);
1977
+ }
1978
+ function isNodeError3(error) {
1979
+ return error instanceof Error && "code" in error;
1980
+ }
1917
1981
 
1918
1982
  // src/plugin/createPlugin.ts
1919
1983
  import { createRPCServer } from "vite-dev-rpc";
@@ -1983,7 +2047,8 @@ function vueMcpNext(userOptions = {}) {
1983
2047
  root,
1984
2048
  mcpSseUrl,
1985
2049
  mcpStreamableHttpUrl,
1986
- options.mcpClients
2050
+ options.mcpClients,
2051
+ userOptions
1987
2052
  );
1988
2053
  if (options.printUrl) {
1989
2054
  setTimeout(() => {