@ada-mcp/mcp-server 0.1.9 → 0.1.11

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
@@ -8,25 +8,27 @@ ADA MCP server package that supports:
8
8
 
9
9
  ## 标准安装(Cursor / MCP)
10
10
 
11
- 请使用 **`@ada-mcp/launcher@0.1.3`** 拉起本包(见 [launcher README](../ada-mcp-launcher/README.md)):
11
+ 请使用 **`@ada-mcp/launcher@0.1.7`** 拉起本包(见 [launcher README](../ada-mcp-launcher/README.md)):
12
12
 
13
13
  ```json
14
14
  {
15
15
  "mcpServers": {
16
16
  "ada-mcp": {
17
17
  "command": "pnpm",
18
- "args": ["dlx", "@ada-mcp/launcher@0.1.3"]
18
+ "args": ["dlx", "@ada-mcp/launcher@0.1.7"]
19
19
  }
20
20
  }
21
21
  }
22
22
  ```
23
23
 
24
- 本包版本:**`@ada-mcp/mcp-server@0.1.7`**(由 launcher 默认拉取)。
24
+ 本包版本:**`@ada-mcp/mcp-server@0.1.10`**(由 launcher 默认拉取;依赖锁定 `playwright@1.59.1`)。
25
25
 
26
26
  直接调试本包(无 launcher 拉包前测速):
27
27
 
28
28
  ```bash
29
- pnpm dlx @ada-mcp/mcp-server@0.1.7
29
+ pnpm dlx @ada-mcp/mcp-server@0.1.10
30
+ # npx 等价:
31
+ npx -y @ada-mcp/mcp-server@0.1.10
30
32
  ```
31
33
 
32
34
  ## 启动时自动安装依赖(默认仅 Playwright)
@@ -52,12 +54,12 @@ pnpm dlx @ada-mcp/mcp-server@0.1.7
52
54
  - `ADA_PLAYWRIGHT_INSTALL_TIMEOUT_MS`:浏览器下载超时(默认 15 分钟)
53
55
  - `ADA_INSTALL_STRATEGY_TIMEOUT_MS`:npm 装包超时(默认 2 分钟)
54
56
 
55
- ## 代理与镜像(`0.1.3+`)
57
+ ## 代理与镜像(`0.1.10+` 推荐)
56
58
 
57
59
  | 阶段 | 自动探测最快镜像 |
58
60
  |------|------------------|
59
61
  | `pnpm dlx @ada-mcp/launcher` | **是** — 拉包前测速(推荐) |
60
- | `pnpm dlx @ada-mcp/mcp-server` | tarball 仍走本机源;**同次安装的依赖**由 `preinstall` 测速(0.1.5+) |
62
+ | `pnpm dlx @ada-mcp/mcp-server` | tarball 仍走本机源;**同次安装的依赖**由 `preinstall` 测速(仅写入官方 Playwright CDN,`0.1.9+`) |
61
63
  | 启动后 `install-deps` | 是 — 内置国内镜像测速(**无需配置**) |
62
64
 
63
65
  默认 npm 探测候选(按优先级,延迟相同取靠前):阿里云 npmmirror → 腾讯云 → 华为云 → npm 官方。
@@ -81,26 +83,28 @@ pnpm dlx @ada-mcp/mcp-server@0.1.7
81
83
  在标准 `args` 后追加,例如安装全部依赖:
82
84
 
83
85
  ```json
84
- "args": ["dlx", "@ada-mcp/launcher@0.1.3", "--install-deps=all"]
86
+ "args": ["dlx", "@ada-mcp/launcher@0.1.7", "--install-deps=all"]
85
87
  ```
86
88
 
87
89
  ## Cursor MCP 配置
88
90
 
89
- 与上文**标准配置**相同:`pnpm` + `dlx @ada-mcp/launcher@0.1.3`。
91
+ **pnpm(推荐)**:`pnpm` + `dlx @ada-mcp/launcher@0.1.7`
90
92
 
91
- Windows 若找不到 `pnpm`,可写完整路径,例如 `C:\\Users\\<你>\\AppData\\Roaming\\npm\\pnpm.cmd`,或改用 npx:
93
+ **npx 等价**(`launcher@0.1.7+`):`npx` + `-y @ada-mcp/launcher@0.1.7`(内层同样 `npx -y` mcp-server,测速逻辑与 pnpm 一致)
92
94
 
93
95
  ```json
94
96
  {
95
97
  "mcpServers": {
96
98
  "ada-mcp": {
97
99
  "command": "npx",
98
- "args": ["-y", "@ada-mcp/mcp-server"]
100
+ "args": ["-y", "@ada-mcp/launcher@0.1.7"]
99
101
  }
100
102
  }
101
103
  }
102
104
  ```
103
105
 
106
+ Windows 若找不到 `pnpm`,可将 `command` 改为 `pnpm.cmd` 绝对路径;无 pnpm 时只能直接 `npx -y @ada-mcp/mcp-server@0.1.10`(无 launcher 拉包测速)。
107
+
104
108
  ## Remote mode
105
109
 
106
110
  Set API key in environment variable first:
package/dist/cli.cjs CHANGED
@@ -3568,6 +3568,39 @@ function resolveBundledPlaywrightCli() {
3568
3568
  const version = String(JSON.parse(raw).version ?? "");
3569
3569
  return { command: "node", cliArgs: [import_node_path5.default.join(root, "cli.js")], version };
3570
3570
  }
3571
+ function resolveChromiumBrowserVersion() {
3572
+ try {
3573
+ const browsersPath = require2.resolve("playwright-core/browsers.json");
3574
+ const raw = (0, import_node_fs.readFileSync)(browsersPath, "utf8");
3575
+ const parsed = JSON.parse(raw);
3576
+ const chromium = parsed.browsers?.find((b) => b.name === "chromium");
3577
+ return String(chromium?.browserVersion ?? "").trim();
3578
+ } catch {
3579
+ return "";
3580
+ }
3581
+ }
3582
+ function playwrightChromiumZipUrl(host, browserVersion) {
3583
+ const h = normalizeHostUrl(host);
3584
+ const base = h.includes("cdn.npmmirror.com/binaries/playwright") || h.endsWith("/binaries/playwright") ? "https://cdn.npmmirror.com/binaries/playwright" : h.includes("npmmirror.com") && !h.includes("/mirrors/playwright") ? "https://npmmirror.com/mirrors/playwright" : h;
3585
+ return `${base}/builds/cft/${browserVersion}/win64/chrome-win64.zip`;
3586
+ }
3587
+ async function probePlaywrightBrowserArtifact(host, browserVersion) {
3588
+ const url = playwrightChromiumZipUrl(host, browserVersion);
3589
+ const started = Date.now();
3590
+ const controller = new AbortController();
3591
+ const timer = setTimeout(() => controller.abort(), 8e3);
3592
+ try {
3593
+ const response = await fetch(url, { method: "HEAD", redirect: "follow", signal: controller.signal });
3594
+ if (response.status === 200) {
3595
+ return Date.now() - started;
3596
+ }
3597
+ return null;
3598
+ } catch {
3599
+ return null;
3600
+ } finally {
3601
+ clearTimeout(timer);
3602
+ }
3603
+ }
3571
3604
  function requiredAppiumDrivers(config) {
3572
3605
  return Array.from(new Set(config.appium.requiredDrivers ?? []));
3573
3606
  }
@@ -3677,7 +3710,6 @@ async function resolveCompatibleDriverSpecs(driver) {
3677
3710
  return Array.from(new Set(specs));
3678
3711
  }
3679
3712
  var detectedBestRegistryByKey = /* @__PURE__ */ new Map();
3680
- var detectedBestPlaywrightHost = null;
3681
3713
  var PROGRESS_STEPS = [
3682
3714
  "deps.ensure.start",
3683
3715
  "registry.probe.start",
@@ -3859,40 +3891,43 @@ async function probePlaywrightHostLatency(host) {
3859
3891
  }
3860
3892
  return best;
3861
3893
  }
3862
- async function detectBestPlaywrightHost(config) {
3863
- if (detectedBestPlaywrightHost) {
3864
- return detectedBestPlaywrightHost;
3865
- }
3894
+ async function rankPlaywrightHosts(config) {
3866
3895
  const candidates = playwrightHostCandidates(config);
3867
- progress("playwright.host.probe.start", { candidates });
3896
+ const browserVersion = resolveChromiumBrowserVersion();
3897
+ progress("playwright.host.probe.start", { candidates, browserVersion: browserVersion || void 0 });
3868
3898
  const probeResults = await Promise.all(candidates.map(async (candidate) => {
3869
3899
  progress("playwright.host.probe.try", { candidate });
3870
- const latency = await probePlaywrightHostLatency(candidate);
3871
- progress("playwright.host.probe.result", { candidate, latencyMs: latency });
3872
- return { candidate, latency };
3900
+ const artifactLatency = browserVersion ? await probePlaywrightBrowserArtifact(candidate, browserVersion) : null;
3901
+ const rootLatency = await probePlaywrightHostLatency(candidate);
3902
+ const latency = artifactLatency ?? rootLatency;
3903
+ const artifactOk = artifactLatency !== null;
3904
+ progress("playwright.host.probe.result", {
3905
+ candidate,
3906
+ latencyMs: latency,
3907
+ artifactOk,
3908
+ browserVersion: browserVersion || void 0
3909
+ });
3910
+ return { candidate, latency, artifactOk, priority: playwrightHostPriorityIndex(candidates, candidate) };
3873
3911
  }));
3874
- let best = candidates[0] ?? PLAYWRIGHT_HOST_FALLBACK;
3875
- let bestLatency = Number.POSITIVE_INFINITY;
3876
- let bestPriority = Number.POSITIVE_INFINITY;
3877
- for (const { candidate, latency } of probeResults) {
3878
- if (latency === null)
3879
- continue;
3880
- const priority = playwrightHostPriorityIndex(candidates, candidate);
3881
- if (latency < bestLatency || latency === bestLatency && priority < bestPriority) {
3882
- best = candidate;
3883
- bestLatency = latency;
3884
- bestPriority = priority;
3912
+ const reachable = probeResults.filter((x) => x.latency !== null);
3913
+ const withArtifact = reachable.filter((x) => x.artifactOk);
3914
+ const pool = withArtifact.length > 0 ? withArtifact : reachable;
3915
+ pool.sort((a, b) => {
3916
+ if (a.artifactOk !== b.artifactOk) {
3917
+ return a.artifactOk ? -1 : 1;
3885
3918
  }
3886
- }
3887
- detectedBestPlaywrightHost = best;
3888
- log("info", {
3889
- event: "deps.playwright.host.auto-selected",
3890
- details: {
3891
- selected: best,
3892
- candidates
3919
+ if (a.latency !== b.latency) {
3920
+ return (a.latency ?? 0) - (b.latency ?? 0);
3893
3921
  }
3922
+ return a.priority - b.priority;
3894
3923
  });
3895
- return best;
3924
+ const ranked = pool.map((x) => x.candidate);
3925
+ for (const candidate of candidates) {
3926
+ if (!ranked.includes(candidate)) {
3927
+ ranked.push(candidate);
3928
+ }
3929
+ }
3930
+ return ranked.length > 0 ? ranked : [...candidates];
3896
3931
  }
3897
3932
  async function runInstallWithPriority(config, packages, onLogLine) {
3898
3933
  const npmProxy = await detectBestRegistry(config, npmProxyRegistry());
@@ -4035,16 +4070,37 @@ async function installPlaywrightBrowser(config, onLogLine, options) {
4035
4070
  if (targets.length > 0) {
4036
4071
  installArgs.push(...targets);
4037
4072
  }
4038
- const selectedHost = await detectBestPlaywrightHost(config);
4039
- onLogLine?.(`[playwright] \u4F7F\u7528\u5185\u7F6E playwright@${version} CLI\uFF0C\u955C\u50CF ${selectedHost}\uFF0C\u76EE\u6807: ${targets.length ? targets.join(",") : "all"}${options?.force ? " (--force)" : ""}`);
4073
+ const rankedHosts = await rankPlaywrightHosts(config);
4040
4074
  const timeoutMs = playwrightInstallTimeoutMs();
4041
4075
  onLogLine?.(`[playwright] \u5B89\u88C5\u8D85\u65F6\u4E0A\u9650 ${Math.round(timeoutMs / 1e3)}s\uFF08\u53EF\u7528 ADA_PLAYWRIGHT_INSTALL_TIMEOUT_MS \u8C03\u6574\uFF09`);
4042
- await runCommand2(command, installArgs, {
4043
- env: { PLAYWRIGHT_DOWNLOAD_HOST: selectedHost },
4044
- timeoutMs,
4045
- onLogLine
4046
- });
4047
- progress("playwright.browser.install.done", { selectedHost });
4076
+ let lastError;
4077
+ for (let i = 0; i < rankedHosts.length; i++) {
4078
+ const host = rankedHosts[i];
4079
+ if (i > 0) {
4080
+ onLogLine?.(`[playwright] \u4E0A\u4E00\u955C\u50CF\u5931\u8D25\uFF0C\u6539\u8BD5 ${host}`);
4081
+ }
4082
+ onLogLine?.(`[playwright] \u4F7F\u7528\u5185\u7F6E playwright@${version} CLI\uFF0C\u955C\u50CF ${host}\uFF0C\u76EE\u6807: ${targets.length ? targets.join(",") : "all"}${options?.force ? " (--force)" : ""}`);
4083
+ try {
4084
+ await runCommand2(command, installArgs, {
4085
+ env: { PLAYWRIGHT_DOWNLOAD_HOST: host },
4086
+ timeoutMs,
4087
+ onLogLine
4088
+ });
4089
+ progress("playwright.browser.install.done", { selectedHost: host, attempt: i + 1 });
4090
+ return;
4091
+ } catch (error) {
4092
+ lastError = error;
4093
+ log("warn", {
4094
+ event: "deps.playwright.browser.install.host.fail",
4095
+ details: {
4096
+ host,
4097
+ attempt: i + 1,
4098
+ message: error instanceof Error ? error.message : String(error)
4099
+ }
4100
+ });
4101
+ }
4102
+ }
4103
+ throw lastError instanceof Error ? lastError : new Error(String(lastError ?? "playwright browser install failed"));
4048
4104
  }
4049
4105
  async function checkPlaywrightLaunchable() {
4050
4106
  try {
@@ -8477,7 +8533,7 @@ async function startMcpServer() {
8477
8533
  mcpServers: {
8478
8534
  "ada-mcp": {
8479
8535
  command: "pnpm",
8480
- args: ["dlx", "@ada-mcp/launcher@0.1.3"]
8536
+ args: ["dlx", "@ada-mcp/launcher@0.1.7"]
8481
8537
  }
8482
8538
  }
8483
8539
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ada-mcp/mcp-server",
3
- "version": "0.1.9",
3
+ "version": "0.1.11",
4
4
  "description": "ADA MCP server for web/mobile automation (stdio + remote HTTP)",
5
5
  "private": false,
6
6
  "type": "commonjs",
@@ -31,7 +31,8 @@
31
31
  "access": "public"
32
32
  },
33
33
  "dependencies": {
34
- "@modelcontextprotocol/sdk": "^1.17.5",
34
+ "@modelcontextprotocol/sdk": "1.17.5",
35
+ "zod": "3.25.76",
35
36
  "express": "^5.2.1",
36
37
  "jimp": "^1.6.0",
37
38
  "js-yaml": "^4.1.0",
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * pnpm dlx 安装本包时:preinstall 测速 registry + Playwright CDN,写入 .npmrc 与 .ada-mcp-playwright-host
3
+ * pnpm dlx / npx -y 安装本包时:preinstall 测速 registry + Playwright CDN,写入 .npmrc 与 .ada-mcp-playwright-host
4
4
  */
5
5
  import fs from "node:fs";
6
6
  import path from "node:path";