web-fetcher-mcp 1.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.
- package/README.md +185 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +278 -0
- package/dist/index.js.map +1 -0
- package/dist/tools/click-element.d.ts +3 -0
- package/dist/tools/click-element.d.ts.map +1 -0
- package/dist/tools/click-element.js +166 -0
- package/dist/tools/click-element.js.map +1 -0
- package/dist/tools/focus-input.d.ts +3 -0
- package/dist/tools/focus-input.d.ts.map +1 -0
- package/dist/tools/focus-input.js +78 -0
- package/dist/tools/focus-input.js.map +1 -0
- package/dist/tools/tapd-bug-fetcher.d.ts +20 -0
- package/dist/tools/tapd-bug-fetcher.d.ts.map +1 -0
- package/dist/tools/tapd-bug-fetcher.js +376 -0
- package/dist/tools/tapd-bug-fetcher.js.map +1 -0
- package/dist/tools/type-input.d.ts +3 -0
- package/dist/tools/type-input.d.ts.map +1 -0
- package/dist/tools/type-input.js +97 -0
- package/dist/tools/type-input.js.map +1 -0
- package/dist/tools/utils/utils.d.ts +2 -0
- package/dist/tools/utils/utils.d.ts.map +1 -0
- package/dist/tools/utils/utils.js +7 -0
- package/dist/tools/utils/utils.js.map +1 -0
- package/dist/tools/web-page-fetcher.d.ts +3 -0
- package/dist/tools/web-page-fetcher.d.ts.map +1 -0
- package/dist/tools/web-page-fetcher.js +100 -0
- package/dist/tools/web-page-fetcher.js.map +1 -0
- package/dist/types/index.d.ts +73 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/browser.d.ts +6 -0
- package/dist/utils/browser.d.ts.map +1 -0
- package/dist/utils/browser.js +95 -0
- package/dist/utils/browser.js.map +1 -0
- package/dist/utils/config.d.ts +7 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +11 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/cookies.d.ts +5 -0
- package/dist/utils/cookies.d.ts.map +1 -0
- package/dist/utils/cookies.js +46 -0
- package/dist/utils/cookies.js.map +1 -0
- package/dist/utils/images.d.ts +5 -0
- package/dist/utils/images.d.ts.map +1 -0
- package/dist/utils/images.js +59 -0
- package/dist/utils/images.js.map +1 -0
- package/dist/utils/login-check.d.ts +4 -0
- package/dist/utils/login-check.d.ts.map +1 -0
- package/dist/utils/login-check.js +110 -0
- package/dist/utils/login-check.js.map +1 -0
- package/dist/utils/page-content.d.ts +4 -0
- package/dist/utils/page-content.d.ts.map +1 -0
- package/dist/utils/page-content.js +139 -0
- package/dist/utils/page-content.js.map +1 -0
- package/package.json +47 -0
package/README.md
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# Web Page Fetcher MCP
|
|
2
|
+
|
|
3
|
+
一个通用的 MCP 工具,可以获取任意网页的内容(包括文字和图片),支持需要登录的页面。
|
|
4
|
+
|
|
5
|
+
## 功能概述
|
|
6
|
+
|
|
7
|
+
- 获取任意网页的文本内容
|
|
8
|
+
- 下载网页中的图片并转换为 Base64
|
|
9
|
+
- 支持需要登录的页面
|
|
10
|
+
- 自动保存和复用登录状态(Cookie)
|
|
11
|
+
- 可自定义内容选择器,精准提取页面特定区域
|
|
12
|
+
|
|
13
|
+
## 使用方法
|
|
14
|
+
|
|
15
|
+
### 工具 1: fetch-web-page
|
|
16
|
+
|
|
17
|
+
获取网页内容(文字和图片)
|
|
18
|
+
|
|
19
|
+
### 参数说明
|
|
20
|
+
|
|
21
|
+
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|
|
22
|
+
|------|------|------|--------|------|
|
|
23
|
+
| url | string | 是 | - | 网页的完整 URL |
|
|
24
|
+
| contentSelector | string | 否 | 'body' | 内容选择器,用于指定要提取内容的 HTML 元素 |
|
|
25
|
+
| downloadImages | boolean | 否 | true | 是否下载图片 |
|
|
26
|
+
| loginMode | string | 否 | 'skip' | 登录模式:skip/auto/manual |
|
|
27
|
+
| waitForLogin | boolean | 否 | false | 检测到需要登录时是否等待用户手动登录 |
|
|
28
|
+
|
|
29
|
+
### 登录模式说明
|
|
30
|
+
|
|
31
|
+
- **skip** (默认): 不检测登录状态,直接获取页面内容
|
|
32
|
+
- **auto**: 使用保存的 Cookie 自动登录
|
|
33
|
+
- **manual**: 打开浏览器等待用户手动完成登录
|
|
34
|
+
|
|
35
|
+
### 示例调用
|
|
36
|
+
|
|
37
|
+
#### 普通网页抓取
|
|
38
|
+
```json
|
|
39
|
+
{
|
|
40
|
+
"name": "fetch-web-page",
|
|
41
|
+
"arguments": {
|
|
42
|
+
"url": "https://cloud.tencent.com/document/product/866/43106"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
#### 抓取特定区域内容
|
|
48
|
+
```json
|
|
49
|
+
{
|
|
50
|
+
"name": "fetch-web-page",
|
|
51
|
+
"arguments": {
|
|
52
|
+
"url": "https://example.com/article/123",
|
|
53
|
+
"contentSelector": ".article-content"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
#### 需要登录的页面(首次)
|
|
59
|
+
```json
|
|
60
|
+
{
|
|
61
|
+
"name": "fetch-web-page",
|
|
62
|
+
"arguments": {
|
|
63
|
+
"url": "https://internal.example.com/dashboard",
|
|
64
|
+
"loginMode": "manual",
|
|
65
|
+
"waitForLogin": true
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
#### 需要登录的页面(后续)
|
|
71
|
+
```json
|
|
72
|
+
{
|
|
73
|
+
"name": "fetch-web-page",
|
|
74
|
+
"arguments": {
|
|
75
|
+
"url": "https://internal.example.com/dashboard",
|
|
76
|
+
"loginMode": "auto"
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
### 工具 2: focus-input-element
|
|
84
|
+
|
|
85
|
+
获取页面输入框焦点,支持通过 CSS 选择器定位元素。
|
|
86
|
+
|
|
87
|
+
#### 参数说明
|
|
88
|
+
|
|
89
|
+
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|
|
90
|
+
|------|------|------|--------|------|
|
|
91
|
+
| url | string | 否 | 'current' | 网页 URL,使用 'current' 则操作当前已打开的页面 |
|
|
92
|
+
| selector | string | 是 | - | CSS 选择器,支持类名、ID、属性选择器等 |
|
|
93
|
+
| useExistingPage | boolean | 否 | true | 是否使用已存在的页面 |
|
|
94
|
+
|
|
95
|
+
#### 示例调用
|
|
96
|
+
|
|
97
|
+
##### 通过 ID 获取焦点
|
|
98
|
+
```json
|
|
99
|
+
{
|
|
100
|
+
"name": "focus-input-element",
|
|
101
|
+
"arguments": {
|
|
102
|
+
"selector": "#username"
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
##### 通过类名获取焦点
|
|
108
|
+
```json
|
|
109
|
+
{
|
|
110
|
+
"name": "focus-input-element",
|
|
111
|
+
"arguments": {
|
|
112
|
+
"selector": ".search-input"
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
##### 通过属性选择器获取焦点
|
|
118
|
+
```json
|
|
119
|
+
{
|
|
120
|
+
"name": "focus-input-element",
|
|
121
|
+
"arguments": {
|
|
122
|
+
"selector": "input[name='email']"
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
##### 操作特定页面的输入框
|
|
128
|
+
```json
|
|
129
|
+
{
|
|
130
|
+
"name": "focus-input-element",
|
|
131
|
+
"arguments": {
|
|
132
|
+
"url": "https://example.com/login",
|
|
133
|
+
"selector": "#password"
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
#### 返回结果
|
|
139
|
+
|
|
140
|
+
成功时返回元素信息:
|
|
141
|
+
```
|
|
142
|
+
✅ 成功获取焦点!
|
|
143
|
+
|
|
144
|
+
元素信息:
|
|
145
|
+
- 标签: input
|
|
146
|
+
- 类型: text
|
|
147
|
+
- ID: username
|
|
148
|
+
- Name: user
|
|
149
|
+
- Class: form-control
|
|
150
|
+
- Placeholder: 请输入用户名
|
|
151
|
+
- 当前值:
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## 数据存储
|
|
155
|
+
|
|
156
|
+
- **Cookie 存储位置**: `~/.web-fetcher-mcp/cookies.json`
|
|
157
|
+
- **图片存储位置**: `~/.web-fetcher-mcp/images/`
|
|
158
|
+
|
|
159
|
+
## 系统要求
|
|
160
|
+
|
|
161
|
+
- Node.js 18+
|
|
162
|
+
- Google Chrome 浏览器
|
|
163
|
+
|
|
164
|
+
## 安装和运行
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
# 安装依赖
|
|
168
|
+
npm install
|
|
169
|
+
|
|
170
|
+
# 构建
|
|
171
|
+
npm run build
|
|
172
|
+
|
|
173
|
+
# 运行
|
|
174
|
+
npm start
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## 使用已有 Chrome 实例(推荐)
|
|
178
|
+
|
|
179
|
+
如需使用日常浏览器的书签和登录状态,先用以下命令启动 Chrome:
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
"C:\Program Files\Google\Chrome\Application\chrome.exe" --remote-debugging-port=9222
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
然后 MCP 工具会自动连接到该实例。
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
3
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { fetchWebPage } from './tools/web-page-fetcher.js';
|
|
7
|
+
import { focusInputElement } from './tools/focus-input.js';
|
|
8
|
+
import { typeInputElement } from './tools/type-input.js';
|
|
9
|
+
import { clickElement } from './tools/click-element.js';
|
|
10
|
+
// 定义工具列表
|
|
11
|
+
const tools = [
|
|
12
|
+
{
|
|
13
|
+
name: 'fetch-web-page',
|
|
14
|
+
description: '获取任意网页的内容(包括文字和图片)。支持需要登录的页面,首次访问需要手动登录时会自动保存登录状态。',
|
|
15
|
+
inputSchema: z.object({
|
|
16
|
+
url: z.string().describe('网页的完整 URL,例如:https://cloud.tencent.com/document/product/866/43106'),
|
|
17
|
+
contentSelector: z.string().optional().default('body').describe('内容选择器,用于指定要提取内容的 HTML 元素,默认值为 "body"'),
|
|
18
|
+
downloadImages: z.boolean().optional().default(true).describe('是否下载图片,默认值为 true'),
|
|
19
|
+
loginMode: z.enum(['auto', 'manual', 'skip']).optional().default('skip').describe('登录模式:skip - 不检测登录(默认);auto - 使用保存的 Cookie 自动登录;manual - 手动登录(首次访问或 Cookie 过期时使用)'),
|
|
20
|
+
waitForLogin: z.boolean().optional().default(false).describe('当检测到需要登录时是否等待用户手动登录,默认值为 false'),
|
|
21
|
+
}),
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
name: 'focus-input-element',
|
|
25
|
+
description: '通过 CSS 选择器获取页面上的输入框焦点。支持类名、ID、标签名等任意 CSS 选择器。',
|
|
26
|
+
inputSchema: z.object({
|
|
27
|
+
url: z.string().optional().default('current').describe('网页 URL,如果是 current 则使用当前已打开的页面'),
|
|
28
|
+
selector: z.string().describe('CSS 选择器,例如:#username、.search-input、input[name="email"]'),
|
|
29
|
+
useExistingPage: z.boolean().optional().default(true).describe('是否使用已存在的页面,默认 true'),
|
|
30
|
+
}),
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: 'type-input-element',
|
|
34
|
+
description: '在指定的输入框中输入文本内容。支持先清空输入框,支持输入后按回车。',
|
|
35
|
+
inputSchema: z.object({
|
|
36
|
+
url: z.string().optional().default('current').describe('网页 URL,如果是 current 则使用当前已打开的页面'),
|
|
37
|
+
selector: z.string().describe('CSS 选择器,例如:#kw、.search-input、input[name="wd"]'),
|
|
38
|
+
text: z.string().describe('要输入的文本内容'),
|
|
39
|
+
clearFirst: z.boolean().optional().default(true).describe('是否先清空输入框,默认 true'),
|
|
40
|
+
pressEnter: z.boolean().optional().default(false).describe('输入后是否按回车键,默认 false'),
|
|
41
|
+
useExistingPage: z.boolean().optional().default(true).describe('是否使用已存在的页面,默认 true'),
|
|
42
|
+
}),
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: 'click-element',
|
|
46
|
+
description: '点击页面上的指定元素。支持按钮、链接、复选框等任意可点击元素。',
|
|
47
|
+
inputSchema: z.object({
|
|
48
|
+
url: z.string().optional().default('current').describe('网页 URL,如果是 current 则使用当前已打开的页面'),
|
|
49
|
+
selector: z.string().describe('CSS 选择器,例如:#login-btn、.submit-button、button[type="submit"]'),
|
|
50
|
+
useExistingPage: z.boolean().optional().default(true).describe('是否使用已存在的页面,默认 true'),
|
|
51
|
+
}),
|
|
52
|
+
},
|
|
53
|
+
];
|
|
54
|
+
// 创建 MCP Server
|
|
55
|
+
const server = new Server({
|
|
56
|
+
name: 'web-fetcher-mcp',
|
|
57
|
+
version: '1.0.0',
|
|
58
|
+
}, {
|
|
59
|
+
capabilities: {
|
|
60
|
+
tools: {},
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
// 处理工具列表请求
|
|
64
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
65
|
+
return {
|
|
66
|
+
tools: tools.map((tool) => ({
|
|
67
|
+
name: tool.name,
|
|
68
|
+
description: tool.description,
|
|
69
|
+
inputSchema: tool.inputSchema,
|
|
70
|
+
})),
|
|
71
|
+
};
|
|
72
|
+
});
|
|
73
|
+
// 处理工具调用请求
|
|
74
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
75
|
+
const { name, arguments: args } = request.params;
|
|
76
|
+
if (name === 'fetch-web-page') {
|
|
77
|
+
const validatedArgs = tools[0].inputSchema.parse(args);
|
|
78
|
+
console.error(`正在获取网页: ${validatedArgs.url}`);
|
|
79
|
+
const result = await fetchWebPage(validatedArgs.url, validatedArgs.contentSelector || 'body', validatedArgs.downloadImages !== false, validatedArgs.loginMode || 'skip', validatedArgs.waitForLogin || false);
|
|
80
|
+
if (result.success && result.content) {
|
|
81
|
+
const contentParts = [];
|
|
82
|
+
// 添加表单元素信息(如果有)
|
|
83
|
+
if (result.content.formElements && result.content.formElements.length > 0) {
|
|
84
|
+
contentParts.push({
|
|
85
|
+
type: 'text',
|
|
86
|
+
text: `\n📋 页面表单元素 (${result.content.formElements.length} 个):\n`,
|
|
87
|
+
});
|
|
88
|
+
result.content.formElements.forEach((el, i) => {
|
|
89
|
+
let elInfo = `${i + 1}. <${el.tagName}`;
|
|
90
|
+
if (el.type)
|
|
91
|
+
elInfo += ` type="${el.type}"`;
|
|
92
|
+
if (el.id)
|
|
93
|
+
elInfo += ` id="${el.id}"`;
|
|
94
|
+
if (el.name)
|
|
95
|
+
elInfo += ` name="${el.name}"`;
|
|
96
|
+
if (el.placeholder)
|
|
97
|
+
elInfo += ` placeholder="${el.placeholder.slice(0, 30)}"`;
|
|
98
|
+
if (el.value)
|
|
99
|
+
elInfo += ` value="${el.value.slice(0, 30)}"`;
|
|
100
|
+
elInfo += `>\n 选择器: ${el.selector}\n`;
|
|
101
|
+
contentParts.push({
|
|
102
|
+
type: 'text',
|
|
103
|
+
text: elInfo,
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
// 添加 HTML 骨架(如果有)
|
|
108
|
+
if (result.content.htmlSkeleton) {
|
|
109
|
+
contentParts.push({
|
|
110
|
+
type: 'text',
|
|
111
|
+
text: `\n🦴 HTML 骨架:\n\`\`\`html\n${result.content.htmlSkeleton}\n\`\`\`\n`,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
// 添加文本内容
|
|
115
|
+
if (result.content.text) {
|
|
116
|
+
contentParts.push({
|
|
117
|
+
type: 'text',
|
|
118
|
+
text: `\n📝 页面文本内容:\n${result.content.text}`,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
// 添加下载的图片
|
|
122
|
+
if (result.content.downloadedImages && result.content.downloadedImages.length > 0) {
|
|
123
|
+
contentParts.push({
|
|
124
|
+
type: 'text',
|
|
125
|
+
text: `\n已下载 ${result.content.downloadedImages.length} 张图片:\n`,
|
|
126
|
+
});
|
|
127
|
+
for (let i = 0; i < result.content.downloadedImages.length; i++) {
|
|
128
|
+
const img = result.content.downloadedImages[i];
|
|
129
|
+
contentParts.push({
|
|
130
|
+
type: 'text',
|
|
131
|
+
text: `图片 ${i + 1}: ${img.filename}\n原始链接:${img.originalUrl}\n`,
|
|
132
|
+
});
|
|
133
|
+
contentParts.push({
|
|
134
|
+
type: 'image',
|
|
135
|
+
data: img.base64,
|
|
136
|
+
mimeType: 'image/png',
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
else if (result.content.images && result.content.images.length > 0) {
|
|
141
|
+
contentParts.push({
|
|
142
|
+
type: 'text',
|
|
143
|
+
text: `\n找到的图片链接 (${result.content.images.length} 张):\n` +
|
|
144
|
+
result.content.images.map((img, i) => `${i + 1}. ${img}`).join('\n'),
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
return { content: contentParts };
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
return {
|
|
151
|
+
content: [{
|
|
152
|
+
type: 'text',
|
|
153
|
+
text: `获取失败:${result.error || '未知错误'}`,
|
|
154
|
+
}],
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
if (name === 'focus-input-element') {
|
|
159
|
+
const validatedArgs = tools[1].inputSchema.parse(args);
|
|
160
|
+
console.error(`正在获取输入框焦点: ${validatedArgs.selector}`);
|
|
161
|
+
const result = await focusInputElement(validatedArgs.url, validatedArgs.selector, validatedArgs.useExistingPage !== false);
|
|
162
|
+
if (result.success) {
|
|
163
|
+
const info = result.elementInfo;
|
|
164
|
+
let responseText = `✅ 成功获取焦点!\n\n`;
|
|
165
|
+
responseText += `元素信息:\n`;
|
|
166
|
+
responseText += `- 标签: ${info?.tagName}\n`;
|
|
167
|
+
if (info?.type)
|
|
168
|
+
responseText += `- 类型: ${info.type}\n`;
|
|
169
|
+
if (info?.id)
|
|
170
|
+
responseText += `- ID: ${info.id}\n`;
|
|
171
|
+
if (info?.name)
|
|
172
|
+
responseText += `- Name: ${info.name}\n`;
|
|
173
|
+
if (info?.className)
|
|
174
|
+
responseText += `- Class: ${info.className}\n`;
|
|
175
|
+
if (info?.placeholder)
|
|
176
|
+
responseText += `- Placeholder: ${info.placeholder}\n`;
|
|
177
|
+
if (info?.value)
|
|
178
|
+
responseText += `- 当前值: ${info.value}\n`;
|
|
179
|
+
return {
|
|
180
|
+
content: [{
|
|
181
|
+
type: 'text',
|
|
182
|
+
text: responseText,
|
|
183
|
+
}],
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
return {
|
|
188
|
+
content: [{
|
|
189
|
+
type: 'text',
|
|
190
|
+
text: `❌ 获取焦点失败:${result.error || '未知错误'}`,
|
|
191
|
+
}],
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
if (name === 'type-input-element') {
|
|
196
|
+
const validatedArgs = tools[2].inputSchema.parse(args);
|
|
197
|
+
console.error(`正在输入内容到: ${validatedArgs.selector}`);
|
|
198
|
+
const result = await typeInputElement(validatedArgs.url, validatedArgs.selector, validatedArgs.text, validatedArgs.clearFirst !== false, validatedArgs.pressEnter || false, validatedArgs.useExistingPage !== false);
|
|
199
|
+
if (result.success) {
|
|
200
|
+
const info = result.elementInfo;
|
|
201
|
+
let responseText = `✅ 输入成功!\n\n`;
|
|
202
|
+
responseText += `输入内容: ${validatedArgs.text}\n`;
|
|
203
|
+
if (validatedArgs.pressEnter)
|
|
204
|
+
responseText += `已按回车键\n`;
|
|
205
|
+
responseText += `\n元素信息:\n`;
|
|
206
|
+
responseText += `- 标签: ${info?.tagName}\n`;
|
|
207
|
+
if (info?.id)
|
|
208
|
+
responseText += `- ID: ${info.id}\n`;
|
|
209
|
+
if (info?.name)
|
|
210
|
+
responseText += `- Name: ${info.name}\n`;
|
|
211
|
+
if (info?.value)
|
|
212
|
+
responseText += `- 当前值: ${info.value}\n`;
|
|
213
|
+
return {
|
|
214
|
+
content: [{
|
|
215
|
+
type: 'text',
|
|
216
|
+
text: responseText,
|
|
217
|
+
}],
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
return {
|
|
222
|
+
content: [{
|
|
223
|
+
type: 'text',
|
|
224
|
+
text: `❌ 输入失败:${result.error || '未知错误'}`,
|
|
225
|
+
}],
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
if (name === 'click-element') {
|
|
230
|
+
const validatedArgs = tools[3].inputSchema.parse(args);
|
|
231
|
+
console.error(`正在点击元素: ${validatedArgs.selector}`);
|
|
232
|
+
const result = await clickElement(validatedArgs.url, validatedArgs.selector, validatedArgs.useExistingPage !== false);
|
|
233
|
+
if (result.success) {
|
|
234
|
+
const info = result.elementInfo;
|
|
235
|
+
let responseText = `✅ 点击成功!\n\n`;
|
|
236
|
+
responseText += `元素信息:\n`;
|
|
237
|
+
responseText += `- 标签: ${info?.tagName}\n`;
|
|
238
|
+
if (info?.type)
|
|
239
|
+
responseText += `- 类型: ${info.type}\n`;
|
|
240
|
+
if (info?.id)
|
|
241
|
+
responseText += `- ID: ${info.id}\n`;
|
|
242
|
+
if (info?.name)
|
|
243
|
+
responseText += `- Name: ${info.name}\n`;
|
|
244
|
+
if (info?.className)
|
|
245
|
+
responseText += `- Class: ${info.className}\n`;
|
|
246
|
+
if (info?.text)
|
|
247
|
+
responseText += `- 文本: ${info.text}\n`;
|
|
248
|
+
if (info?.disabled)
|
|
249
|
+
responseText += `- 状态: 禁用\n`;
|
|
250
|
+
return {
|
|
251
|
+
content: [{
|
|
252
|
+
type: 'text',
|
|
253
|
+
text: responseText,
|
|
254
|
+
}],
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
return {
|
|
259
|
+
content: [{
|
|
260
|
+
type: 'text',
|
|
261
|
+
text: `❌ 点击失败:${result.error || '未知错误'}`,
|
|
262
|
+
}],
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
throw new Error(`未知工具:${name}`);
|
|
267
|
+
});
|
|
268
|
+
// 启动服务器
|
|
269
|
+
async function main() {
|
|
270
|
+
const transport = new StdioServerTransport();
|
|
271
|
+
await server.connect(transport);
|
|
272
|
+
console.error('MCP Server 已启动,等待连接...');
|
|
273
|
+
}
|
|
274
|
+
main().catch((error) => {
|
|
275
|
+
console.error('服务器启动失败:', error);
|
|
276
|
+
process.exit(1);
|
|
277
|
+
});
|
|
278
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"click-element.d.ts","sourceRoot":"","sources":["../../src/tools/click-element.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAIvD,wBAAsB,YAAY,CAChC,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,eAAe,GAAE,OAAc,GAC9B,OAAO,CAAC,kBAAkB,CAAC,CA2L7B"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { getBrowser, getPage, closeBrowser } from '../utils/browser.js';
|
|
2
|
+
// 点击页面元素
|
|
3
|
+
export async function clickElement(url, selector, useExistingPage = true) {
|
|
4
|
+
let browserConnection = null;
|
|
5
|
+
try {
|
|
6
|
+
// 获取浏览器实例
|
|
7
|
+
browserConnection = await getBrowser();
|
|
8
|
+
const { browser, useExistingBrowser } = browserConnection;
|
|
9
|
+
// 获取页面
|
|
10
|
+
const page = await getPage(browser, useExistingBrowser, useExistingPage ? 'current' : url);
|
|
11
|
+
// 如果需要导航到指定 URL
|
|
12
|
+
if (!useExistingPage && url !== 'current') {
|
|
13
|
+
await page.goto(url, { waitUntil: 'networkidle2', timeout: 60000 });
|
|
14
|
+
}
|
|
15
|
+
console.error(`正在查找元素: ${selector}`);
|
|
16
|
+
// 首先尝试使用 page.evaluate 直接查找元素(更可靠)
|
|
17
|
+
const elementInfo = await page.evaluate((sel) => {
|
|
18
|
+
// 尝试多种选择器方式
|
|
19
|
+
let element = null;
|
|
20
|
+
// 1. 直接尝试 CSS 选择器
|
|
21
|
+
try {
|
|
22
|
+
element = document.querySelector(sel);
|
|
23
|
+
}
|
|
24
|
+
catch (e) {
|
|
25
|
+
// 选择器语法错误,继续尝试其他方式
|
|
26
|
+
}
|
|
27
|
+
// 2. 如果是 href 包含选择器,尝试通过属性查找
|
|
28
|
+
if (!element && sel.includes('[href')) {
|
|
29
|
+
const match = sel.match(/href\*?="?([^"\]]*)"?\]/);
|
|
30
|
+
if (match) {
|
|
31
|
+
const hrefValue = match[1];
|
|
32
|
+
const links = document.querySelectorAll('a');
|
|
33
|
+
for (const link of Array.from(links)) {
|
|
34
|
+
if (link.href && link.href.includes(hrefValue)) {
|
|
35
|
+
element = link;
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// 3. 如果是类名选择器,尝试通过类名查找
|
|
42
|
+
if (!element && sel.startsWith('.')) {
|
|
43
|
+
const className = sel.substring(1);
|
|
44
|
+
const elements = document.querySelectorAll('*');
|
|
45
|
+
for (const el of Array.from(elements)) {
|
|
46
|
+
if (el.className && el.className.includes && el.className.includes(className)) {
|
|
47
|
+
element = el;
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// 4. 如果是文本内容选择器,尝试通过文本查找
|
|
53
|
+
if (!element && sel.includes(':contains')) {
|
|
54
|
+
const match = sel.match(/:contains\(["']?([^"']*)["']?\)/);
|
|
55
|
+
if (match) {
|
|
56
|
+
const text = match[1];
|
|
57
|
+
const allElements = document.querySelectorAll('*');
|
|
58
|
+
for (const el of Array.from(allElements)) {
|
|
59
|
+
if (el.textContent && el.textContent.trim() === text) {
|
|
60
|
+
element = el;
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (!element) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
// 获取元素信息
|
|
70
|
+
return {
|
|
71
|
+
tagName: element.tagName.toLowerCase(),
|
|
72
|
+
type: element.getAttribute('type') || undefined,
|
|
73
|
+
name: element.getAttribute('name') || undefined,
|
|
74
|
+
id: element.id || undefined,
|
|
75
|
+
className: element.className || undefined,
|
|
76
|
+
text: element.textContent?.trim() || undefined,
|
|
77
|
+
disabled: element.disabled || false,
|
|
78
|
+
foundSelector: sel
|
|
79
|
+
};
|
|
80
|
+
}, selector);
|
|
81
|
+
if (!elementInfo) {
|
|
82
|
+
await closeBrowser(browser, useExistingBrowser, true);
|
|
83
|
+
return {
|
|
84
|
+
success: false,
|
|
85
|
+
error: `未找到元素: ${selector}`
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
// 使用 page.evaluate 点击元素(更可靠)
|
|
89
|
+
const clickResult = await page.evaluate((sel) => {
|
|
90
|
+
// 重新查找元素并点击
|
|
91
|
+
let element = null;
|
|
92
|
+
// 同样的查找逻辑
|
|
93
|
+
try {
|
|
94
|
+
element = document.querySelector(sel);
|
|
95
|
+
}
|
|
96
|
+
catch (e) { }
|
|
97
|
+
if (!element && sel.includes('[href')) {
|
|
98
|
+
const match = sel.match(/href\*?="?([^"\]]*)"?\]/);
|
|
99
|
+
if (match) {
|
|
100
|
+
const hrefValue = match[1];
|
|
101
|
+
const links = document.querySelectorAll('a');
|
|
102
|
+
for (const link of Array.from(links)) {
|
|
103
|
+
if (link.href && link.href.includes(hrefValue)) {
|
|
104
|
+
element = link;
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (!element && sel.startsWith('.')) {
|
|
111
|
+
const className = sel.substring(1);
|
|
112
|
+
const elements = document.querySelectorAll('*');
|
|
113
|
+
for (const el of Array.from(elements)) {
|
|
114
|
+
if (el.className && el.className.includes && el.className.includes(className)) {
|
|
115
|
+
element = el;
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (element) {
|
|
121
|
+
// 滚动到元素可见
|
|
122
|
+
element.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
123
|
+
// 模拟点击
|
|
124
|
+
const clickEvent = new MouseEvent('click', {
|
|
125
|
+
bubbles: true,
|
|
126
|
+
cancelable: true,
|
|
127
|
+
view: window
|
|
128
|
+
});
|
|
129
|
+
element.dispatchEvent(clickEvent);
|
|
130
|
+
// 也尝试原生点击
|
|
131
|
+
if (element.click) {
|
|
132
|
+
element.click();
|
|
133
|
+
}
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
return false;
|
|
137
|
+
}, selector);
|
|
138
|
+
if (!clickResult) {
|
|
139
|
+
await closeBrowser(browser, useExistingBrowser, true);
|
|
140
|
+
return {
|
|
141
|
+
success: false,
|
|
142
|
+
error: `点击元素失败: ${selector}`
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
console.error(`成功点击元素: ${elementInfo.tagName}`);
|
|
146
|
+
// 保持浏览器打开
|
|
147
|
+
await closeBrowser(browser, useExistingBrowser, true);
|
|
148
|
+
return {
|
|
149
|
+
success: true,
|
|
150
|
+
elementInfo
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
catch (error) {
|
|
154
|
+
console.error('点击元素失败:', error);
|
|
155
|
+
// 发生错误时保持浏览器打开
|
|
156
|
+
if (browserConnection) {
|
|
157
|
+
const { browser, useExistingBrowser } = browserConnection;
|
|
158
|
+
await closeBrowser(browser, useExistingBrowser, true);
|
|
159
|
+
}
|
|
160
|
+
return {
|
|
161
|
+
success: false,
|
|
162
|
+
error: error.message || '未知错误'
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=click-element.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"click-element.js","sourceRoot":"","sources":["../../src/tools/click-element.ts"],"names":[],"mappings":"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"}
|