@mearl/mcp-server 2.0.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.
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * mearl-mcp-install - 用户友好的安装命令
4
+ *
5
+ * 使用方式:
6
+ * mearl-mcp-install
7
+ * MEARL_EXTENSION_ID=xxx mearl-mcp-install
8
+ */
9
+ export {};
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * mearl-mcp-install - 用户友好的安装命令
4
+ *
5
+ * 使用方式:
6
+ * mearl-mcp-install
7
+ * MEARL_EXTENSION_ID=xxx mearl-mcp-install
8
+ */
9
+ import { installNativeHost } from '@mearl/native-host';
10
+ console.log('🚀 Mearl MCP Installer\n');
11
+ const extensionId = process.env.MEARL_EXTENSION_ID;
12
+ // Install both host manifests so MCP and Skills integrations can coexist.
13
+ const success = await installNativeHost({
14
+ mode: 'both',
15
+ ...(extensionId ? { extensionId } : {}),
16
+ });
17
+ process.exit(success ? 0 : 1);
@@ -0,0 +1,23 @@
1
+ /**
2
+ * MCP 客户端配置定义
3
+ */
4
+ export interface MCPClientConfig {
5
+ name: string;
6
+ configPath: string;
7
+ useServersFormat?: boolean;
8
+ useTomlFormat?: boolean;
9
+ }
10
+ export declare const MCP_CLIENTS: Record<string, MCPClientConfig>;
11
+ export declare function isNpxMode(): boolean;
12
+ export declare function getMCPServerConfig(useServersFormat?: boolean, useNpx?: boolean): any;
13
+ /**
14
+ * 检测已安装的 MCP 客户端
15
+ * @returns 已安装的客户端 ID 列表
16
+ */
17
+ export declare function detectInstalledClients(): string[];
18
+ /**
19
+ * 检测单个 MCP 客户端是否已安装
20
+ * @param clientId 客户端 ID
21
+ * @returns 是否已安装
22
+ */
23
+ export declare function isClientInstalled(clientId: string): boolean;
@@ -0,0 +1,153 @@
1
+ /**
2
+ * MCP 客户端配置定义
3
+ */
4
+ import { join, dirname } from 'path';
5
+ import { homedir, platform } from 'os';
6
+ import { existsSync } from 'fs';
7
+ /**
8
+ * 获取跨平台的配置文件路径
9
+ * @param paths 不同平台的路径配置
10
+ * @returns 当前平台对应的完整路径
11
+ */
12
+ function getPlatformConfigPath(paths) {
13
+ const os = platform();
14
+ const basePath = homedir();
15
+ if (os === 'win32' && paths.win32) {
16
+ return join(basePath, paths.win32);
17
+ }
18
+ else if (os === 'darwin' && paths.darwin) {
19
+ return join(basePath, paths.darwin);
20
+ }
21
+ else if (paths.linux) {
22
+ return join(basePath, paths.linux);
23
+ }
24
+ // Fallback: 使用 darwin 路径作为默认
25
+ return join(basePath, paths.darwin || paths.linux || paths.win32 || '');
26
+ }
27
+ export const MCP_CLIENTS = {
28
+ 'vscode-copilot': {
29
+ name: 'VSCode Copilot',
30
+ configPath: getPlatformConfigPath({
31
+ win32: join(process.env.APPDATA || '', 'Code/User/mcp.json'),
32
+ darwin: 'Library/Application Support/Code/User/mcp.json',
33
+ linux: '.config/Code/User/mcp.json',
34
+ }),
35
+ useServersFormat: true,
36
+ },
37
+ 'claude-code': {
38
+ name: 'Claude Code',
39
+ configPath: getPlatformConfigPath({
40
+ win32: join(process.env.APPDATA || '', 'Claude Code/mcp_config.json'),
41
+ darwin: '.config/claude-code/mcp_config.json',
42
+ linux: '.config/claude-code/mcp_config.json',
43
+ }),
44
+ },
45
+ cursor: {
46
+ name: 'Cursor',
47
+ configPath: getPlatformConfigPath({
48
+ win32: join(process.env.APPDATA || '', 'Cursor/mcp_config.json'),
49
+ darwin: '.cursor/mcp_config.json',
50
+ linux: '.cursor/mcp_config.json',
51
+ }),
52
+ },
53
+ qoder: {
54
+ name: 'Qoder',
55
+ configPath: getPlatformConfigPath({
56
+ win32: join(process.env.APPDATA || '', 'Qoder/mcp_config.json'),
57
+ darwin: 'Library/Application Support/Qoder/mcp_config.json',
58
+ linux: '.config/qoder/mcp_config.json',
59
+ }),
60
+ },
61
+ codex: {
62
+ name: 'Codex',
63
+ configPath: getPlatformConfigPath({
64
+ win32: '.codex/config.toml',
65
+ darwin: '.codex/config.toml',
66
+ linux: '.codex/config.toml',
67
+ }),
68
+ useTomlFormat: true,
69
+ },
70
+ };
71
+ // 检测是否通过 npx 运行
72
+ export function isNpxMode() {
73
+ // 检查 npm_execpath 环境变量
74
+ const execPath = process.env.npm_execpath || '';
75
+ if (execPath.includes('npx')) {
76
+ return true;
77
+ }
78
+ // 检查 npm_config_user_agent
79
+ const userAgent = process.env.npm_config_user_agent || '';
80
+ if (userAgent.includes('npx')) {
81
+ return true;
82
+ }
83
+ // 检查 process.argv[1] 是否包含 _npx
84
+ const argv1 = process.argv[1] || '';
85
+ if (argv1.includes('_npx') || argv1.includes('.npm/_npx')) {
86
+ return true;
87
+ }
88
+ // 检查 npm_command 是否为 exec (npx 使用 npm exec)
89
+ const npmCommand = process.env.npm_command || '';
90
+ if (npmCommand === 'exec') {
91
+ return true;
92
+ }
93
+ return false;
94
+ }
95
+ // 获取 MCP Server 配置模板
96
+ export function getMCPServerConfig(useServersFormat, useNpx) {
97
+ if (useServersFormat) {
98
+ // VS Code 格式
99
+ if (useNpx) {
100
+ return {
101
+ type: 'stdio',
102
+ command: 'npx',
103
+ args: ['-y', '@mearl/mcp-server'],
104
+ };
105
+ }
106
+ return {
107
+ type: 'stdio',
108
+ command: 'mearl-mcp-server',
109
+ };
110
+ }
111
+ // Claude Code/Cursor 格式
112
+ if (useNpx) {
113
+ return {
114
+ command: 'npx',
115
+ args: ['-y', '@mearl/mcp-server'],
116
+ env: {},
117
+ };
118
+ }
119
+ return {
120
+ command: 'mearl-mcp-server',
121
+ args: [],
122
+ env: {},
123
+ };
124
+ }
125
+ /**
126
+ * 检测已安装的 MCP 客户端
127
+ * @returns 已安装的客户端 ID 列表
128
+ */
129
+ export function detectInstalledClients() {
130
+ const installed = [];
131
+ for (const [id, config] of Object.entries(MCP_CLIENTS)) {
132
+ // 检查配置文件的父目录是否存在
133
+ // 因为配置文件本身可能不存在,但如果应用已安装,其配置目录应该存在
134
+ const configDir = dirname(config.configPath);
135
+ if (existsSync(configDir)) {
136
+ installed.push(id);
137
+ }
138
+ }
139
+ return installed;
140
+ }
141
+ /**
142
+ * 检测单个 MCP 客户端是否已安装
143
+ * @param clientId 客户端 ID
144
+ * @returns 是否已安装
145
+ */
146
+ export function isClientInstalled(clientId) {
147
+ const config = MCP_CLIENTS[clientId];
148
+ if (!config) {
149
+ return false;
150
+ }
151
+ const configDir = dirname(config.configPath);
152
+ return existsSync(configDir);
153
+ }
@@ -0,0 +1,120 @@
1
+ export interface MtopRequest {
2
+ id: number;
3
+ timestamp: string;
4
+ timestampMs: number;
5
+ method: string;
6
+ url: string;
7
+ apiName: string;
8
+ status: number;
9
+ statusText: string;
10
+ headers: Array<{
11
+ name: string;
12
+ value: string;
13
+ }>;
14
+ responseHeaders: Array<{
15
+ name: string;
16
+ value: string;
17
+ }>;
18
+ queryString: Record<string, string>;
19
+ postData: Record<string, any> | null;
20
+ responseBody: any;
21
+ duration?: number;
22
+ proxyData?: any;
23
+ }
24
+ export interface ConsoleLog {
25
+ level: 'log' | 'warn' | 'error' | 'info';
26
+ message: string;
27
+ timestamp: number;
28
+ /** 来源文件和行号,格式 "filename.js:42",仅在可获取时存在 */
29
+ source?: string;
30
+ args: any[];
31
+ }
32
+ export interface WaitForRequestParams {
33
+ pattern: string;
34
+ timeout?: number;
35
+ includeExisting?: boolean;
36
+ }
37
+ export interface GetRequestsParams {
38
+ count?: number;
39
+ filter?: string;
40
+ since?: number;
41
+ }
42
+ export interface GetLogsParams {
43
+ level?: 'log' | 'warn' | 'error' | 'info' | 'all';
44
+ since?: number;
45
+ limit?: number;
46
+ filter?: string;
47
+ }
48
+ export interface SetMockParams {
49
+ apiName: string;
50
+ mockData: any;
51
+ enabled?: boolean;
52
+ duration?: number;
53
+ conditions?: Record<string, any>;
54
+ }
55
+ export interface GetApiSchemaParams {
56
+ api: string;
57
+ version?: string;
58
+ }
59
+ export interface GetSelectedElementParams {
60
+ includeOuterHTML?: boolean;
61
+ includeScreenshot?: boolean;
62
+ }
63
+ export interface RequestsResponse {
64
+ meta: {
65
+ /** 实际返回的请求数量 */
66
+ count: number;
67
+ /** 缓冲区中符合过滤条件的总请求数 */
68
+ totalMatched: number;
69
+ /** 缓冲区中的总请求数(未过滤) */
70
+ totalInBuffer: number;
71
+ /** 应用的过滤器(如果有) */
72
+ filter?: string;
73
+ /** 时间过滤器(秒) */
74
+ since?: number;
75
+ /** 是否包含请求/响应体 */
76
+ includeBody: boolean;
77
+ /** 是否包含请求/响应头 */
78
+ includeHeaders: boolean;
79
+ /** 提取的字段(如果有) */
80
+ fields?: string[];
81
+ /** 是否只返回键结构 */
82
+ keysOnly: boolean;
83
+ };
84
+ /** 请求数据列表 */
85
+ requests: MtopRequest[];
86
+ }
87
+ export interface LogsResponse {
88
+ meta: {
89
+ /** 实际返回的日志数量 */
90
+ count: number;
91
+ /** 符合过滤条件的总日志数 */
92
+ totalMatched: number;
93
+ /** 应用的日志级别过滤 */
94
+ level: string;
95
+ /** 时间过滤器(秒) */
96
+ since?: number;
97
+ /** 应用的过滤模式 */
98
+ filter?: string;
99
+ };
100
+ /** 日志数据列表 */
101
+ logs: ConsoleLog[];
102
+ }
103
+ export interface ScreenshotResponse {
104
+ meta: {
105
+ /** 截图格式 */
106
+ format: 'png' | 'jpeg';
107
+ /** 截图宽度 */
108
+ width: number;
109
+ /** 截图高度 */
110
+ height: number;
111
+ /** 截图数据大小(字节) */
112
+ size: number;
113
+ /** 截图的页面 URL */
114
+ url: string;
115
+ /** 截图的页面标题 */
116
+ title: string;
117
+ };
118
+ /** Base64 编码的截图数据 */
119
+ data: string;
120
+ }
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ // 消息类型定义
2
+ export {};
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * mearl-mcp-uninstall - 卸载清理脚本
4
+ *
5
+ * 使用方式:
6
+ * npx @mearl/mcp-server --uninstall
7
+ * 或 mearl-mcp-uninstall (如果全局安装)
8
+ */
9
+ export {};
@@ -0,0 +1,152 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * mearl-mcp-uninstall - 卸载清理脚本
4
+ *
5
+ * 使用方式:
6
+ * npx @mearl/mcp-server --uninstall
7
+ * 或 mearl-mcp-uninstall (如果全局安装)
8
+ */
9
+ import { unlinkSync, existsSync, readFileSync, writeFileSync } from 'fs';
10
+ import { join } from 'path';
11
+ import { homedir, platform } from 'os';
12
+ import { execSync } from 'child_process';
13
+ import prompts from 'prompts';
14
+ import { HOST_NAME } from './constants.js';
15
+ import { MCP_CLIENTS } from './mcp-clients.js';
16
+ // 获取 Native Messaging Host 配置目录
17
+ function getNativeHostDir() {
18
+ const os = platform();
19
+ if (os === 'darwin') {
20
+ return join(homedir(), 'Library/Application Support/Google/Chrome/NativeMessagingHosts');
21
+ }
22
+ else if (os === 'linux') {
23
+ return join(homedir(), '.config/google-chrome/NativeMessagingHosts');
24
+ }
25
+ else if (os === 'win32') {
26
+ throw new Error('Windows 需要手动删除注册表项,请参考 README.md');
27
+ }
28
+ else {
29
+ throw new Error(`不支持的平台: ${os}`);
30
+ }
31
+ }
32
+ // 检查是否全局安装
33
+ function isGloballyInstalled() {
34
+ try {
35
+ const cmd = platform() === 'win32' ? 'where' : 'which';
36
+ execSync(`${cmd} mearl-mcp-server`, { encoding: 'utf-8', stdio: 'pipe' });
37
+ return true;
38
+ }
39
+ catch {
40
+ return false;
41
+ }
42
+ }
43
+ // 清理 MCP 配置文件中的 mearl
44
+ function cleanMCPConfig(configPath, clientConfig) {
45
+ try {
46
+ if (!existsSync(configPath)) {
47
+ return false;
48
+ }
49
+ const content = readFileSync(configPath, 'utf-8');
50
+ const config = JSON.parse(content);
51
+ const useServersFormat = clientConfig.useServersFormat;
52
+ let hasConfig = false;
53
+ if (useServersFormat) {
54
+ // VS Code 格式:检查 servers
55
+ if (config.servers && config.servers['mearl']) {
56
+ delete config.servers['mearl'];
57
+ hasConfig = true;
58
+ }
59
+ }
60
+ else {
61
+ // Claude Code/Cursor 格式:检查 mcpServers
62
+ if (config.mcpServers && config.mcpServers['mearl']) {
63
+ delete config.mcpServers['mearl'];
64
+ hasConfig = true;
65
+ }
66
+ }
67
+ if (!hasConfig) {
68
+ return false;
69
+ }
70
+ // 写回文件
71
+ writeFileSync(configPath, JSON.stringify(config, null, 2));
72
+ return true;
73
+ }
74
+ catch (error) {
75
+ console.error(` ⚠️ 清理配置失败: ${error instanceof Error ? error.message : String(error)}`);
76
+ return false;
77
+ }
78
+ }
79
+ // 卸载主函数
80
+ async function uninstall() {
81
+ console.log('🗑️ Mearl MCP 卸载\n');
82
+ try {
83
+ // 1. 清理 Native Messaging Host 配置
84
+ console.log('清理 Native Messaging Host...');
85
+ const hostDir = getNativeHostDir();
86
+ const manifestPath = join(hostDir, `${HOST_NAME}.json`);
87
+ const wrapperPath = join(hostDir, `${HOST_NAME}-launcher.sh`);
88
+ let hasDeleted = false;
89
+ if (existsSync(manifestPath)) {
90
+ unlinkSync(manifestPath);
91
+ console.log(`✅ 删除配置文件`);
92
+ hasDeleted = true;
93
+ }
94
+ if (existsSync(wrapperPath)) {
95
+ unlinkSync(wrapperPath);
96
+ hasDeleted = true;
97
+ }
98
+ if (!hasDeleted) {
99
+ console.log('未找到配置文件');
100
+ }
101
+ // 2. 检查全局安装
102
+ console.log('\n检查 npm 全局安装...');
103
+ if (isGloballyInstalled()) {
104
+ console.log('⚠️ 请手动卸载: npm uninstall -g @mearl/mcp-server');
105
+ }
106
+ else {
107
+ console.log('✅ 未检测到全局安装');
108
+ }
109
+ // 3. 清理 MCP 客户端配置
110
+ console.log('\n清理 MCP 客户端配置...');
111
+ // 检测哪些客户端有配置文件
112
+ const availableClients = Object.entries(MCP_CLIENTS)
113
+ .filter(([_, client]) => existsSync(client.configPath))
114
+ .map(([key, client]) => ({
115
+ title: client.name,
116
+ value: key,
117
+ }));
118
+ if (availableClients.length === 0) {
119
+ console.log('未找到 MCP 配置');
120
+ }
121
+ else {
122
+ const response = await prompts({
123
+ type: 'multiselect',
124
+ name: 'clients',
125
+ message: '选择要清理的客户端:',
126
+ choices: availableClients,
127
+ instructions: false,
128
+ hint: '空格选择,回车确认',
129
+ });
130
+ if (response.clients && response.clients.length > 0) {
131
+ for (const clientKey of response.clients) {
132
+ const client = MCP_CLIENTS[clientKey];
133
+ if (cleanMCPConfig(client.configPath, client)) {
134
+ console.log(`✅ 已清理 ${client.name}`);
135
+ }
136
+ else {
137
+ console.log(`未找到 ${client.name} 配置`);
138
+ }
139
+ }
140
+ }
141
+ else {
142
+ console.log('已取消');
143
+ }
144
+ }
145
+ console.log('\n✅ 卸载完成!');
146
+ }
147
+ catch (error) {
148
+ console.error('\n❌ 卸载失败:', error instanceof Error ? error.message : String(error));
149
+ process.exit(1);
150
+ }
151
+ }
152
+ uninstall();
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@mearl/mcp-server",
3
+ "version": "2.0.0",
4
+ "description": "MCP Server for Mearl - enables AI to interact with Chrome browser requests and logs",
5
+ "mcpName": "io.github.F-loat/mearl",
6
+ "type": "module",
7
+ "main": "dist/index.js",
8
+ "bin": {
9
+ "@mearl/mcp-server": "./dist/index.js",
10
+ "mearl-mcp-server": "./dist/index.js",
11
+ "mearl-mcp-configure": "./dist/configure.js",
12
+ "mearl-mcp-uninstall": "./dist/uninstall.js"
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "README.md"
17
+ ],
18
+ "keywords": [
19
+ "mcp",
20
+ "chrome-extension",
21
+ "devtools",
22
+ "mearl",
23
+ "ai"
24
+ ],
25
+ "author": "",
26
+ "license": "ISC",
27
+ "publishConfig": {
28
+ "registry": "https://registry.npmjs.org"
29
+ },
30
+ "dependencies": {
31
+ "@modelcontextprotocol/sdk": "^1.0.4",
32
+ "prompts": "^2.4.2",
33
+ "@mearl/client": "2.0.0",
34
+ "@mearl/native-host": "2.0.0"
35
+ },
36
+ "devDependencies": {
37
+ "@types/node": "^24.9.1",
38
+ "@types/prompts": "^2.4.9",
39
+ "typescript": "^5.8.3"
40
+ },
41
+ "scripts": {
42
+ "build": "rm -rf dist/ && tsc",
43
+ "dev": "tsc --watch",
44
+ "start": "node dist/index.js",
45
+ "setup": "pnpm build && npm link",
46
+ "typecheck": "tsc --noEmit"
47
+ }
48
+ }