@mearl/mcp-server 2.0.2 → 2.1.0
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 +1 -0
- package/dist/index.js +59 -32
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
- 📝 **browser_get_logs**: 获取控制台日志
|
|
10
10
|
- 🎭 **browser_set_mock**: 动态设置 Mock 数据
|
|
11
11
|
- 🌐 **browser_list**: 统一列出普通浏览器和托管浏览器,返回默认目标、类型及连接状态
|
|
12
|
+
- 📴 **browser_release**: 释放 debugger/CDP 控制并保留浏览器与全部标签页
|
|
12
13
|
- 🚀 **browser_launch / browser_close**: 启动或关闭独立 Profile 的托管 Chrome
|
|
13
14
|
- 🌐 **browser_page_snapshot**: 首次获取页面结构和可交互元素
|
|
14
15
|
- ⚡ **browser_page_click/type/hover/scroll/press/upload**: 执行页面动作,默认内置观察,返回通知、可交互控件和焦点等高置信度信号
|
package/dist/index.js
CHANGED
|
@@ -22,7 +22,10 @@ import { tmpdir } from 'os';
|
|
|
22
22
|
import { join, dirname } from 'path';
|
|
23
23
|
import { spawn } from 'child_process';
|
|
24
24
|
import { fileURLToPath } from 'url';
|
|
25
|
+
import { createRequire } from 'module';
|
|
25
26
|
import { RESPONSE_SIZE_SMALL, RESPONSE_SIZE_MEDIUM, RESPONSE_SIZE_LARGE, RESPONSE_SIZE_MAX, } from './constants.js';
|
|
27
|
+
const require = createRequire(import.meta.url);
|
|
28
|
+
const MCP_SERVER_VERSION = require('../package.json').version;
|
|
26
29
|
// 日志输出到 stderr(不影响 stdio 通信)
|
|
27
30
|
const LOG_FILE = join(tmpdir(), 'mearl-mcp-server.log');
|
|
28
31
|
const log = (...args) => {
|
|
@@ -245,35 +248,32 @@ function formatResponseWithSizeCheck(result, toolName, args) {
|
|
|
245
248
|
},
|
|
246
249
|
];
|
|
247
250
|
}
|
|
248
|
-
// 策略 5: 超超大响应(>1MB 压缩)-
|
|
249
|
-
const truncateSize = RESPONSE_SIZE_MAX;
|
|
250
|
-
const truncatedStr = compactStr.substring(0, truncateSize);
|
|
251
|
+
// 策略 5: 超超大响应(>1MB 压缩)- 返回可解析的诊断信息
|
|
251
252
|
const suggestions = getOptimizationSuggestions(toolName, args, result, stats);
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
stats.largestFields
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
}
|
|
253
|
+
const diagnostic = {
|
|
254
|
+
error: {
|
|
255
|
+
code: 'RESPONSE_TOO_LARGE',
|
|
256
|
+
message: 'The result exceeded the MCP response limit. Narrow the request and retry.',
|
|
257
|
+
originalSizeBytes: compactSize,
|
|
258
|
+
limitBytes: RESPONSE_SIZE_MAX,
|
|
259
|
+
},
|
|
260
|
+
meta: stats.meta,
|
|
261
|
+
largestFields: stats.largestFields?.map(field => ({
|
|
262
|
+
...field,
|
|
263
|
+
percentageOfTotal: Math.round((field.size / compactSize) * 100),
|
|
264
|
+
})),
|
|
265
|
+
suggestions: suggestions.length > 0
|
|
266
|
+
? suggestions
|
|
267
|
+
: [
|
|
268
|
+
'Significantly reduce the data requested',
|
|
269
|
+
'Use "fields" to extract only essential data',
|
|
270
|
+
'Add filters to narrow down results',
|
|
271
|
+
],
|
|
272
|
+
};
|
|
273
273
|
return [
|
|
274
274
|
{
|
|
275
275
|
type: 'text',
|
|
276
|
-
text:
|
|
276
|
+
text: JSON.stringify(diagnostic, null, 2),
|
|
277
277
|
},
|
|
278
278
|
];
|
|
279
279
|
}
|
|
@@ -317,7 +317,7 @@ async function main() {
|
|
|
317
317
|
// 创建 MCP Server
|
|
318
318
|
const server = new Server({
|
|
319
319
|
name: 'mearl',
|
|
320
|
-
version:
|
|
320
|
+
version: MCP_SERVER_VERSION,
|
|
321
321
|
}, {
|
|
322
322
|
capabilities: {
|
|
323
323
|
tools: {},
|
|
@@ -466,6 +466,10 @@ async function main() {
|
|
|
466
466
|
inputSchema: {
|
|
467
467
|
type: 'object',
|
|
468
468
|
properties: {
|
|
469
|
+
tabId: {
|
|
470
|
+
type: 'number',
|
|
471
|
+
description: '目标标签页 ID,从 browser_tab_list 获取;不传时使用当前活动标签页',
|
|
472
|
+
},
|
|
469
473
|
level: {
|
|
470
474
|
type: 'string',
|
|
471
475
|
enum: ['log', 'warn', 'error', 'info', 'all'],
|
|
@@ -494,6 +498,10 @@ async function main() {
|
|
|
494
498
|
inputSchema: {
|
|
495
499
|
type: 'object',
|
|
496
500
|
properties: {
|
|
501
|
+
tabId: {
|
|
502
|
+
type: 'number',
|
|
503
|
+
description: '目标标签页 ID,从 browser_tab_list 获取;不传时使用当前活动标签页',
|
|
504
|
+
},
|
|
497
505
|
apiName: {
|
|
498
506
|
type: 'string',
|
|
499
507
|
description: 'API 名称或正则表达式模式。例如: "mtop.cart.query" 精确匹配, ".*\\.cart\\..*" 匹配所有购物车接口',
|
|
@@ -547,6 +555,10 @@ async function main() {
|
|
|
547
555
|
inputSchema: {
|
|
548
556
|
type: 'object',
|
|
549
557
|
properties: {
|
|
558
|
+
tabId: {
|
|
559
|
+
type: 'number',
|
|
560
|
+
description: '目标标签页 ID,从 browser_tab_list 获取;不传时使用当前活动标签页',
|
|
561
|
+
},
|
|
550
562
|
apiName: {
|
|
551
563
|
type: 'string',
|
|
552
564
|
description: '过滤指定接口,支持正则表达式。例如: "mtop.cart.query" 或 ".*\\.cart\\..*"。不传则返回所有 Mock',
|
|
@@ -964,6 +976,14 @@ async function main() {
|
|
|
964
976
|
required: ['browser'],
|
|
965
977
|
},
|
|
966
978
|
},
|
|
979
|
+
{
|
|
980
|
+
name: 'browser_release',
|
|
981
|
+
description: '释放 Agent 对当前目标浏览器的 debugger/CDP 控制,停止持续采集和会话级临时效果,但保留浏览器与全部标签页。后续浏览器操作仍可自动重新建立控制。',
|
|
982
|
+
inputSchema: {
|
|
983
|
+
type: 'object',
|
|
984
|
+
properties: {},
|
|
985
|
+
},
|
|
986
|
+
},
|
|
967
987
|
{
|
|
968
988
|
name: 'browser_tab_open',
|
|
969
989
|
description: '打开或按 URL 规则复用标签页。默认新建并等待加载完成;reuse=prefer 可优先复用,reuse=require 可限制为只复用。响应的 opened/reused 可用于判断流程结束时是否应关闭该 Tab。',
|
|
@@ -1590,13 +1610,13 @@ async function main() {
|
|
|
1590
1610
|
break;
|
|
1591
1611
|
}
|
|
1592
1612
|
case 'browser_get_logs': {
|
|
1593
|
-
const { level = 'all', since, limit = 100, filter } = args;
|
|
1594
|
-
result = await client.getLogs({ level, since, limit, filter });
|
|
1613
|
+
const { tabId, level = 'all', since, limit = 100, filter } = args;
|
|
1614
|
+
result = await client.getLogs({ tabId, level, since, limit, filter });
|
|
1595
1615
|
break;
|
|
1596
1616
|
}
|
|
1597
1617
|
case 'browser_set_mock': {
|
|
1598
1618
|
const { payloadFile } = args;
|
|
1599
|
-
let { apiName, mockData, fields, enabled, duration, conditions } = args;
|
|
1619
|
+
let { tabId, apiName, mockData, fields, enabled, duration, conditions } = args;
|
|
1600
1620
|
enabled = enabled ?? true;
|
|
1601
1621
|
// 如果提供了 payloadFile,从文件读取 mock 数据
|
|
1602
1622
|
if (payloadFile) {
|
|
@@ -1605,7 +1625,9 @@ async function main() {
|
|
|
1605
1625
|
}
|
|
1606
1626
|
const fileContent = readFileSync(payloadFile, 'utf-8');
|
|
1607
1627
|
const fileData = JSON.parse(fileContent);
|
|
1608
|
-
// 文件内容可以包含 apiName、mockData、fields、enabled、duration、conditions 等参数
|
|
1628
|
+
// 文件内容可以包含 tabId、apiName、mockData、fields、enabled、duration、conditions 等参数
|
|
1629
|
+
if (fileData.tabId !== undefined)
|
|
1630
|
+
tabId = fileData.tabId;
|
|
1609
1631
|
if (fileData.apiName)
|
|
1610
1632
|
apiName = fileData.apiName;
|
|
1611
1633
|
if (fileData.mockData !== undefined)
|
|
@@ -1620,6 +1642,7 @@ async function main() {
|
|
|
1620
1642
|
conditions = fileData.conditions;
|
|
1621
1643
|
}
|
|
1622
1644
|
result = await client.setMock({
|
|
1645
|
+
tabId,
|
|
1623
1646
|
apiName,
|
|
1624
1647
|
mockData,
|
|
1625
1648
|
fields,
|
|
@@ -1630,8 +1653,8 @@ async function main() {
|
|
|
1630
1653
|
break;
|
|
1631
1654
|
}
|
|
1632
1655
|
case 'browser_get_mocks': {
|
|
1633
|
-
const { apiName } = args;
|
|
1634
|
-
result = await client.getMocks({ apiName });
|
|
1656
|
+
const { tabId, apiName } = args;
|
|
1657
|
+
result = await client.getMocks({ tabId, apiName });
|
|
1635
1658
|
break;
|
|
1636
1659
|
}
|
|
1637
1660
|
case 'browser_get_api_schema': {
|
|
@@ -1723,6 +1746,10 @@ async function main() {
|
|
|
1723
1746
|
result = await client.browserClose(args);
|
|
1724
1747
|
break;
|
|
1725
1748
|
}
|
|
1749
|
+
case 'browser_release': {
|
|
1750
|
+
result = await client.browserRelease();
|
|
1751
|
+
break;
|
|
1752
|
+
}
|
|
1726
1753
|
case 'browser_tab_open': {
|
|
1727
1754
|
const { url, active = false, closeExisting = false, reuse = 'never', match, restoreFocusOnClose = false, emulation, group, } = args;
|
|
1728
1755
|
result = await client.tabOpen({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mearl/mcp-server",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "MCP Server for Mearl - enables AI to interact with Chrome browser requests and logs",
|
|
5
5
|
"mcpName": "io.github.F-loat/mearl",
|
|
6
6
|
"type": "module",
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@modelcontextprotocol/sdk": "^1.0.4",
|
|
32
32
|
"prompts": "^2.4.2",
|
|
33
|
-
"@mearl/
|
|
34
|
-
"@mearl/
|
|
33
|
+
"@mearl/client": "2.1.0",
|
|
34
|
+
"@mearl/native-host": "2.1.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@types/node": "^24.9.1",
|